<<< ckmcon.c >>>
17-Mar-86 17:23:10-EST,55266;000000000001
/* From: DPVC@UORDBV.BITNET */
/* DPVC at U of R, Oct 1, add blinking cursor and mouse cursor movement */
/* DPVC at U of R, Sept. 26, fixed book-keeping for scrolling and inserting */
/*  characters and lines */
/* DPVC at U of R, Sept. 25, to fix cursor positioning off the screen, and */
/*  a few other, minor VT100 incompatibilities */
/* DPVC at the University of Rochester, Sept. 9, to add Block Cursor and */
/*  ability to do VT100 graphics characters */
/* By CAM2 and DPVC at the University of Rochester on Sept 6, */
/*  changed bolding from using TextStyle attributes to using a separate bold */
/*  font */
/* By Frank on June 20 - Add parity to all outbound chars using software */
/*  Also, ignore DEL (0177) characters on input. */
/* By Bill on May 29 - Add Key set translation */
/* By WBC3 on Apr 24 - Add ^^, ^@ and ^_.  Also use Pascal strings for */
/*  output in the terminal emulator */
/* By WBC3 on Apr 23 - Add query terminal and be more fastidious about */
/*  ignoring sequences we don't know about */
/* By WBC3 on Apr 22 - Fix tab stops to conform to the rest of the world! */
/* By Bill on Apr 21 - Fix immediate echo problems. */
/*  do less cursor_erase, cursor_draw stuff */
 
/*
 * FILE ckmcon.c
 *
 * Module of mackermit: contains code for the terminal simulation
 * routine.
 */
 
#include "ckmdef.h"
#include "mac/quickdraw.h"              /* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "ckmkkc.h"                     /* common key configure defs */
 
#define MAXLIN      24
#define MAXCOL      80
#define LINEHEIGHT  12
#define CHARWIDTH    6
#define TOPMARGIN    3                  /* Terminal display constants */
#define BOTTOMMARGIN (LINEHEIGHT * MAXLIN + TOPMARGIN)
#define LEFTMARGIN   3
#define RIGHTMARGIN  (CHARWIDTH * MAXCOL + LEFTMARGIN)
#define LINEADJ      3                  /* Amount of char below base line */
 
/* Font Numbers (UoR Mod) to fix bolding problems */
/* These should be placed in the RESOURCE FORK of the executable */
 
#define VT100FONT  128                  /* VT100 Terminal Font (not-bold) */
#define VT100BOLD  129                  /* VT100 Bold Font */
 
/* output character handling */
 
unsigned char obuf[2] = {1,0};          /* single char output buffer */
 
/* Tab settings */
 
/*
#define NUMTABS 9
short tabstops[NUMTABS] = {8,16,24,32,40,48,56,64,72};
*/              /* (UoR) remove old method of tab stops */
 
/* (UoR) do tapstops via an array: 0 means no tab, 1 means tab at that column */
short tabstops[MAXCOL+1] = {0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
   0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,
   0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1};
 
#define USA_SET  0                      /*  (UoR) VT100 character set numbers */
#define UK_SET   1
#define GRAF_SET 2
 
int invert=FALSE,                       /* Flag for inverted terminal mode */
    insert=FALSE,
    topmargin=TOPMARGIN,                /* Edges of adjustable window */
    bottommargin=BOTTOMMARGIN,
    textstyle=0,
    currentfont=VT100FONT,              /* (UoR) currently active font */
    newline=FALSE,                      /* (UoR) linefeed mode by default */
    autowrap=TRUE,                      /* Autowrap on by default */
    relorigin=FALSE,                    /* (UoR) relative origin off */
    screeninvert=FALSE,                 /* (UoR) inverted screen flag */
    autorepeat=TRUE,                    /* (UoR) auto repeat flag */
    graphicsinset[2]={USA_SET,USA_SET}, /* (UoR) current character sets */
    current_set=0;                      /* (UoR) current chosen set */
 
 
char *querystring="\033[?1;2c";         /* Answer we are a VT100 with AVO */
                                        /* (UoR) used to be VT102 */
char *reportstring="\033[0n";           /* (UoR) report that we're OK */
char *noprinter="\033[?13n";            /* (UoR) report no printer */
 
Rect ScreenRect;
        /* (UoR) don't need scrollrect any more
           (use scroll_up and scroll_down), use ScreenRect for mouse check  */
 
RgnHandle dumptr;                       /* Dummy ptr to satisfy scrollbits */
 
/* Screen book keeping variables */
 
char scr[MAXLIN][MAXCOL+1];             /* Characters on the screen */
short nxtlin[MAXLIN], toplin, botlin;   /* Linked list of lines */
int curlin, curcol, abslin;             /* Cursor position */
int savcol, savlin;                     /* Cursor save variables */
int savsty, savfnt, savgrf,
    savmod, savset[2];                  /* (UoR) cursor save variables */
int scrtop, scrbot;                     /* Absolute scrolling region bounds */
int cursor_invert=FALSE,                /* (UoR) for flashing cursor */
    cursor_drawn=FALSE;
long last_flash=0;
int oldlin= -1, oldcol=0;               /* (UoR) for last mouse position */
 
CursHandle mousecursor;                 /* (UoR) the mouse movement pointer */
int theMouse = 128;                     /* (UoR) the mouse pointer res ID */
 
# define CARETTIME 20                   /* (UoR) ticks between flashes */
 
/* Stuff for escape character processing */
 
#define CF_OUTC 0                       /* Just output the char */
#define CF_SESC 1                       /* In a single char escape seq */
#define CF_MESC 2                       /* In a multi char '[' escape seq */
#define CF_TOSS 3                       /* Toss this char */
#define CF_GRF0 4                       /* (UoR) for graphics sequence 0 */
#define CF_GRF1 5                       /* (UoR) for graphics sequence 1 */
 
char prvchr, numone[6], numtwo[6], *numptr;
int num1, num2, charflg=CF_OUTC;
 
extern CSParam controlparam;
 
extern unsigned char dopar();
 
typedef int (*PFI) ();
 
/* Terminal function declarations. */
 
int tab(), back_space(), carriage_return(), line_feed(), bell(), escape_seq(),
    text_mode(), clear_line(), erase_display(), cursor_position(), cursor_up(),
    cursor_down(), cursor_right(), cursor_left(), cursor_save(),
    cursor_restore(), set_scroll_region(), reverse_line_feed(), dummy(),
    delete_char(), insert_mode(), end_insert_mode(), insert_line(),
    delete_line(), query_terminal(), multi_char(), toss_char(),
 
    /* (UoR) for VT100 graphic character set */
 
    graphic_seq0(), graphic_seq1(), control_N(), control_O(),
 
    /* (UoR) for other VT100 functions */
 
    new_line(), request_report(), set_tab(), clear_tab();
 
 
 
/* (UoR) constansts that point to the function definitions for arrow keys */
/*  Used by mouse cursor positioning function */
 
# define UPARROW    100
# define DOWNARROW  101
# define LEFTARROW  102
# define RIGHTARROW 103
 
 
 
 
 
 
 
 
 
/* Terminal control character function command table. */
 
#define MINSINGCMDS 000
#define MAXSINGCMDS 037
 
PFI controltable[MAXSINGCMDS-MINSINGCMDS+1] =
{
    dummy,                              /*  0 */
    dummy,                              /*  1 */
    dummy,                              /*  2 */
    dummy,                              /*  3 */
    dummy,                              /*  4 */
    dummy,                              /*  5 */
    dummy,                              /*  6 */
    bell,                               /*  7 */
    back_space,                         /* 10 */
    tab,                                /* 11 */
    line_feed,                          /* 12 */
    line_feed,                          /* 13 (Vertical tab) */
    line_feed,                          /* 14 (Form feed) */
    carriage_return,                    /* 15 */
    control_N,                          /* 16 (graphic set 1) */   /* (UoR) */
    control_O,                          /* 17 (graphic set 0) */   /* (UoR) */
    dummy,                              /* 20 */
    dummy,                              /* 21 */
    dummy,                              /* 22 */
    dummy,                              /* 23 */
    dummy,                              /* 24 */
    dummy,                              /* 25 */
    dummy,                              /* 26 */
    dummy,                              /* 27 */
    dummy,                              /* 30 */
    dummy,                              /* 31 */
    dummy,                              /* 32 */
    escape_seq,                         /* 33 (Escape) */
    dummy,                              /* 34 */
    dummy,                              /* 35 */
    dummy,                              /* 36 */
    dummy                               /* 37 */
};
 
 
 
 
 
 
 
 
 
#define MINSINGESCS 0040
#define MAXSINGESCS 0137
 
PFI singescapetable[MAXSINGESCS-MINSINGESCS+1] =
{
    dummy,                              /*  40 */
    dummy,                              /*  41 */
    dummy,                              /*  42 */
    toss_char,                          /*  43 '#' */
    dummy,                              /*  44 */
    dummy,                              /*  45 */
    dummy,                              /*  46 */
    dummy,                              /*  47 */
    graphic_seq0,                       /*  50 '(' */   /* (UoR) */
    graphic_seq1,                       /*  51 ')' */   /* (UoR) */
    dummy,                              /*  52 */
    dummy,                              /*  53 */
    dummy,                              /*  54 */
    dummy,                              /*  55 */
    dummy,                              /*  56 */
    dummy,                              /*  57 */
    dummy,                              /*  60 */
    dummy,                              /*  61 */
    dummy,                              /*  62 */
    dummy,                              /*  63 */
    dummy,                              /*  64 */
    dummy,                              /*  65 */
    dummy,                              /*  66 */
    cursor_save,                        /*  67 '7' */
    cursor_restore,                     /*  70 '8' */
    dummy,                              /*  71 */
    dummy,                              /*  72 */
    dummy,                              /*  73 */
    dummy,                              /*  74 '<' */
    dummy,                              /*  75 '=' */
    dummy,                              /*  76 '>' */
    dummy,                              /*  77 */
    dummy,                              /* 100 */
    dummy,                              /* 101 */
    dummy,                              /* 102 */
    dummy,                              /* 103 */
    line_feed,                          /* 104 'D' */
    new_line,                           /* 105 'E' */   /* (UoR) */
    dummy,                              /* 106 */
    dummy,                              /* 107 */
    set_tab,                            /* 110 'H' */   /* (UoR) */
    dummy,                              /* 111 */
    dummy,                              /* 112 */
    dummy,                              /* 113 */
    dummy,                              /* 114 */
    reverse_line_feed,                  /* 115 'M' */
    dummy,                              /* 116 */
    toss_char,                          /* 117 'O' */   /* (UoR) ignore these */
    dummy,                              /* 120 */
    dummy,                              /* 121 */
    dummy,                              /* 122 */
    dummy,                              /* 123 */
    dummy,                              /* 124 */
    dummy,                              /* 125 */
    dummy,                              /* 126 */
    dummy,                              /* 127 */
    dummy,                              /* 130 */
    dummy,                              /* 131 */
    query_terminal,                     /* 132 'Z' */
    multi_char,                         /* 133 '[' */
    dummy,                              /* 134 */
    dummy,                              /* 135 */
    dummy,                              /* 136 */
    dummy                               /* 137 */
};
 
 
 
 
 
 
 
 
 
/* Terminal escape sequence function command table */
 
#define MINMULTESCS 0100
#define MAXMULTESCS 0177
 
PFI escapetable[MAXMULTESCS-MINMULTESCS+1] =
{
    dummy,                              /* 100 */
    cursor_up,                          /* 101 'A' */
    cursor_down,                        /* 102 'B' */
    cursor_right,                       /* 103 'C' */
    cursor_left,                        /* 104 'D' */
    dummy,                              /* 105 */
    dummy,                              /* 106 */
    dummy,                              /* 107 */
    cursor_position,                    /* 110 'H' */
    dummy,                              /* 111 */
    erase_display,                      /* 112 'J' */
    clear_line,                         /* 113 'K' */
    insert_line,                        /* 114 'L' */
    delete_line,                        /* 115 'M' */
    dummy,                              /* 116 */
    dummy,                              /* 117 */
    delete_char,                        /* 120 'P' */
    dummy,                              /* 121 */
    dummy,                              /* 122 */
    dummy,                              /* 123 */
    dummy,                              /* 124 */
    dummy,                              /* 125 */
    dummy,                              /* 126 */
    dummy,                              /* 127 */
    dummy,                              /* 130 */
    dummy,                              /* 131 */
    dummy,                              /* 132 */
    dummy,                              /* 133 */
    dummy,                              /* 134 */
    dummy,                              /* 135 */
    dummy,                              /* 136 */
    dummy,                              /* 137 */
    dummy,                              /* 140 */
    dummy,                              /* 141 */
    dummy,                              /* 142 */
    query_terminal,                     /* 143 'c' */
    dummy,                              /* 144 */
    dummy,                              /* 145 */
    cursor_position,                    /* 146 'f' */
    clear_tab,                          /* 147 'g' */   /* (UoR) */
    insert_mode,                        /* 150 'h' */
    dummy,                              /* 151 */
    dummy,                              /* 152 */
    dummy,                              /* 153 */
    end_insert_mode,                    /* 154 'l' */
    text_mode,                          /* 155 'm' */
    request_report,                     /* 156 'n' */   /* (UoR) */
    dummy,                              /* 157 */
    dummy,                              /* 160 */
    dummy,                              /* 161 */
    set_scroll_region,                  /* 162 'r'*/
    dummy,                              /* 163 */
    dummy,                              /* 164 */
    dummy,                              /* 165 */
    dummy,                              /* 166 */
    dummy,                              /* 167 */
    dummy,                              /* 170 */
    dummy,                              /* 171 */
    dummy,                              /* 172 */
    dummy,                              /* 173 */
    dummy,                              /* 174 */
    dummy,                              /* 175 */
    dummy,                              /* 176 */
    dummy                               /* 177 */
};
 
 
 
 
 
 
 
 
 
/* Connect support routines */
 
consetup()
{
 
    dumptr = NewRgn();
    PenMode(patXor);
    mousecursor = GetCursor(theMouse);  /* (UoR) mouse-move cursor */
    flushio();                          /* Get rid of pending characters */
 
    init_term();                        /* Set up some terminal variables */
    TextFont(VT100FONT);                /* (UoR) Set initial font to VT100 */
    TextMode(srcXor);                   /* (UoR) use XOR mode (for inverse) */
    clear_screen();                     /* Clear the screen */
    home_cursor();                      /* Go to the upper left */
    cursor_save();                      /* Save this position */
    cursor_draw();                      /* (UoR) be sure to draw it */
}
 
/* Input and process all the characters pending on the tty line */
 
inpchars()
{
    int rdcnt;
 
    if ((rdcnt = ttchk()) == 0) return; /* How many chars there?  Ret if 0 */
    cursor_erase();                     /* remove cursor from screen */
    while (rdcnt-- > 0) printit(ttinc(0)); /* Output all those characters */
    flushbuf();                         /* Flush any remaining characters */
    cursor_draw();                      /* put it back */
}
 
 
 
 
 
 
 
 
 
 
/* writeps - write a pascal form string to the serial port.
 *
 */
 
writeps(s)
char *s;
{
  PLONG wcnt, w2;
  int err; char *s2;
 
  w2 = wcnt = *s++;                     /* get count */
  for (s2 = s; w2 > 0; w2--,s2++)       /* add parity */
    *s2 = dopar(*s2);
  err = FSWrite(outnum,&wcnt,s);        /* write the characters */
  if (err != noErr)
    printerr("Bad FSWrite in writeps: ",err);
  return;
  SYM(WRITEPS);
}
 
/*
 * (UoR)
 *
 * Print a string to the screen (used to echo function and meta strings
 * in duplex mode).
 *
 */
 
printps(s)
char *s;
{
   PLONG w2;
   char *s2;
 
   cursor_erase();
 
   w2 = *s++;           /* get count */
   for (s2 = s; w2 > 0; w2--, s2++)
       printit(*s2);    /* print it out, and perform special functions */
 
   cursor_draw();
   return;
   SYM(PRINTPS);
}
 
 
 
 
 
 
 
 
 
/* getindstr - given an indirect (or is it indexed) string and integer
 *             n, return the pointer to the Nth substring.
 *
 * Indirect strings have the count of substrings in the first byte and
 * each string follows with a length byte and a body.
 *
 * Substrings are referenced by 1..N
 *
 */
 
char *getindstr(indstr,n)
char *indstr;
{
  register char *ip = indstr;
  int i;
 
  if (n > *ip++)                        /* too large? */
   return("");                          /* yes, return empty pascal string */
 
  for (i=1; i < n; i++)                 /* scan until we hit the Nth */
   ip += (*ip)+1;                       /* move to next substring */
 
  return(ip);                           /* return ptr to it */
  SYM(GETINDSTR);
}
 
 
 
 
 
 
 
 
 
/* Process a character received from the keyboard */
 
handle_char(evt)
EventRecord *evt;
{
    int code,mods,cidx;
    register KSET *ks;
    unsigned char c;
 
                        /* (UoR) check for auto repeated keys */
    if ((autorepeat == FALSE) && (evt->what == autoKey)) return;
 
    code = (evt->message & keyCodeMask) >> 8;
    mods = (evt->modifiers & MOD_MASK);
 
    cidx = (mods & shiftKey) ?          /* decide if shifted or */
            UC_IDX : LC_IDX;            /*  unshifted map */
 
    ks = *kshdl;                        /* de-reference KSET handle */
 
    if (mods & ks->ctrlmods)            /* control? */
      c = ks->ctrlmap[cidx][code];      /* yes... use control map */
    else
      if (mods & ks->caplmods)          /* else caps lock? */
        c = ks->caplmap[cidx][code];    /* yes, use that map */
     else
       c = ks->normmap[cidx][code];     /* otherwise use normal map */
 
    if (c & FKEYBIT) {                  /* is this a function key? */
      c &= ~FKEYBIT;                    /* clear function bit */
      if (evt->what == autoKey) return; /* (UoR) don't repeat function keys */
      switch (c) {                      /* handle special functions */
        case SPFLBRK:                   /* do long break */
          sendbreak(70);                /* 70*50MS = 3.5 seconds */
          break;
        case SPFSBRK:                   /* do short break */
          sendbreak(5);                 /* 5*50MS = 0.25 seconds */
          break;
        default:                        /* do user defined function */
         writeps(getindstr(*(ks->fcnshdl),(int) c+1));
         if (duplex != 0)               /* (UoR) echo function keys */
            printps(getindstr(*(ks->fcnshdl),(int) c+1));
         break;
      }
      return;                           /* all done */
    }
 
    if (mods & ks->metamods)            /* want to do meta? */
    {
      if (evt->what == autoKey) return; /* (UoR) don't autorepeat metas */
      if (ks->meta8bit)                 /* yes, want 8 bit on? */
        c |= METABIT;                   /* so, turn it on */
      else
      {
        writeps(*(ks->metahdl));        /* else send prefix */
        if (duplex != 0)                /* (UoR) echo metas */
            printps(*(ks->metahdl));
      }
    }
 
                /* (UoR) don't auto repeat control characters */
    if ((c < ' ') && (evt->what == autoKey)) return;
 
    obuf[1] = c;                        /* store character */
    writeps(obuf);                      /* and write it out */
 
    if (duplex != 0)
    {
      cursor_erase();                   /* remove from screen */
      printit((char) c);                /* Echo the char to the screen */
      flushbuf();                       /* flush the character */
      cursor_draw();                    /* put it back */
    }
    return;
    SYM(HANDLE_CHAR);
}
 
 
 
 
 
 
 
 
 
char outbuf[MAXCOL+1];
int outcnt=0, outcol;
 
flushbuf()
{
    Rect r;
 
    if (outcnt == 0) return;            /* Nothing to flush */
 
/* Erase a hole large enough for outcnt chars */
 
    makerect(&r,abslin,outcol,1,outcnt);
 
    EraseRect(&r);              /* (UoR) Use InvertRect instead of fillRect */
    if (invert) InvertRect(&r);
 
    outbuf[outcnt] = '\0';              /* Terminate the string */
    DrawString(outbuf);                 /* Output the string */
    outcnt = 0;                         /* Say no more chars to output */
}
 
buf_char(c)
char c;
{
    if (outcnt == 0) outcol = curcol;   /* No chars in buffer, init column */
    outbuf[outcnt++] = c;               /* Put in the buffer to output later */
}
 
 
 
 
 
 
 
 
 
/*
 *  Printit:
 *      Draws character and updates buffer
 */
 
printit(c)
char c;
{
    PFI funp, lookup();
 
    c &= 0177;
 
    if (c > 0)                          /* (UoR) ignore null characters */
    {
 
       switch (charflg)
       {
          case CF_OUTC:                 /* Just output the char */
            MDrawChar(c);
            break;
 
          case CF_SESC:                 /* In a single char escape seq */
            charflg = CF_OUTC;          /* Reset flag to simple outputting */
            if(funp=lookup(c,singescapetable,MINSINGESCS,MAXSINGESCS))
                (*funp)();              /* Do escape sequence function */
            break;
 
          case CF_GRF0:                 /* (UoR) process graphic characters */
          case CF_GRF1:
            switch (c)
            {
               case 'A':
                  graphicsinset[charflg-CF_GRF0] = UK_SET;
                  break;
               case 'B':
               case '1':
                  graphicsinset[charflg-CF_GRF0] = USA_SET;
                  break;
 
               case '0':
               case '2':
                  graphicsinset[charflg-CF_GRF0] = GRAF_SET;
                  break;
            }
            charflg = CF_OUTC;          /* Reset flag for next character */
            break;
 
          case CF_MESC:                 /* Multichar escape sequence */
            if (c >= 0x20 && c < 0x40)  /* Deal with the modifiers */
            {
                if (c >= '<' && c <= '?') prvchr = c;   /* Handle priv char */
                else if ((c >= '0' && c <= '9') || c == '-' || c == '+')
                {
                    *numptr++ = c;      /* Add the char to the num */
                    *numptr = '\0';     /* Terminate the string */
                }
                else if (c == ';') numptr = numtwo;     /* Go to next number */
                else charflg = CF_OUTC;                 /* (UoR) */
            }
            else                        /* End of sequence */
            {
                if (funp=lookup(c,escapetable,MINMULTESCS,MAXMULTESCS))
                {
                    StringToNum(numone,&num1); /* Translate the numbers */
                    StringToNum(numtwo,&num2);
                    (*funp)();          /* Do the escape sequence function */
                }
                charflg = CF_OUTC;      /* Back to simple outputting */
            }
            break;
 
          case CF_TOSS:                 /* Ignore this char */
            charflg = CF_OUTC;          /* Reset flag */
            break;
        }
    }
}
 
 
 
 
 
 
 
 
 
/*
 * Routine makerect
 *
 * Make a rectangle in r starting on line lin and column col extending
 * numlin lines and numcol characters.
 *
 */
 
makerect(r,lin,col,numlin,numcol)
Rect *r;
int lin, col, numlin, numcol;
{
    r->top = lin * LINEHEIGHT + TOPMARGIN;
    r->left = col * CHARWIDTH + LEFTMARGIN;
    r->bottom = r->top + numlin * LINEHEIGHT;
    r->right = r->left + numcol * CHARWIDTH;
}
 
/*
 *   Lookup:
 *      Lookup a given character in the apropriate character table, and
 *      return a pointer to the appropriate function, if it exists.
 */
 
PFI
lookup(index,table,min,max)
char index;
PFI table[];
int min, max;
{
    if (index > max || index < min)
        return((PFI) NULL);             /* Don't index out of range */
    return(table[index-min]);
}
 
 
/*
 *   Flushio:
 *      Initialize some communications constants, and clear screen and
 *      character buffers.
 */
 
flushio()
{
    int err;
 
    err = KillIO(-6);
    if (err) printerr("Bad input clear",err);
    err = KillIO(-7);
    if (err) printerr("Bad ouput clear",err);
}
 
 
 
 
 
 
 
 
 
 
/* sendbreak - sends a break across the communictions line.
 *
 * The argument is in units of approximately 0.05 seconds (or 50
 * milliseconds).  To send a break of duration 250 milliseconds the
 * argument would be 5; a break of duration 3.5 seconds would be (umm,
 * lets see now) 70.
 *
 */
 
sendbreak(msunit)
{
    int finalticks;
 
/* delay wants 1/60th units.  We have 3/60 (50 ms.) units, convert */
 
    msunit = msunit*3;
 
    Control(outnum,12,&controlparam);   /* Start marking */
/*    SerSetBrk(outnum);                /* start breaking */
    Delay(msunit,&finalticks);          /* delay */
/*    SerClrBrk(outnum);                /* stop breaking */
    Control(outnum,11,&controlparam);   /* Stop marking */
 
}
 
 
 
 
 
 
 
 
 
MDrawChar(chr)
char chr;
{
    PFI funp;
 
/* If it's a control char, do the apropriate function. */
 
    if (chr < ' ')                      /* Is it a control character */
    {
        flushbuf();
        if (funp=lookup(chr,controltable,MINSINGCMDS,MAXSINGCMDS)) (*funp)();
    }
    else if (chr < 0177)                /* Don't do Mac graphic characters */
    {
        switch (graphicsinset[current_set])
        {
            case GRAF_SET:              /* Do VT100 graphics (offset to characte
r in VT100 font) */
                if ((chr >= '_') && (chr <= '~'))  chr +=128;
                break;
 
            case UK_SET:                /* Use pound symbol from VT100 font */
                if (chr == '#') chr = 0375;  /* VT100 pound symbol = 0375 */
                break;
        }
        if (curcol >= MAXCOL)           /* Are we about to wrap around? */
        {
            if (autowrap)               /* If autowrap indicated wrap */
            {
                flushbuf();
                if (newline == FALSE) carriage_return();
                line_feed();
            }
            else
            {
                flushbuf();             /* (UoR) make sure last char is shown */
                back_space();           /* Otherwise just overwrite */
/*              outcnt--; */ /*(UoR) */ /* Overwrite buffered chars too */
            }
        }
        if (insert)                     /* Insert mode? */
        {
            insert_char();              /* Open hole for char if requested */
            erase_char();               /* Erase the old char */
            DrawChar(chr);
        }
        else buf_char(chr);             /* Otherwise just buffer the char */
        scr[curlin][curcol++] = chr;
    }
}
 
 
 
 
 
 
 
 
 
 
/*
 *      Control character functions:
 *              Each of the following allow the mac to simulate
 *              the behavior of a terminal when given the proper
 *              control character.
 */
 
back_space()
{
    if (curcol > 0) relmove(-1,0);
}
 
erase_char()
{
    Rect r;
 
    scr[curlin][curcol] = ' ';          /* Erase char for update */
    makerect(&r,abslin,curcol,1,1);     /* One char by one line */
 
    EraseRect(&r);              /* (UoR) use InvertRect instead of FillRect */
    if (invert) InvertRect(&r);
}
 
tab()
{
    int i;
 
/*    for (i=0; i<NUMTABS; i++)
    {
        if (tabstops[i] > curcol)
        {
            absmove(tabstops[i],abslin);
            return;
        }
    }*/   /* (UoR) remove old method of tabbing */
 
          /* (UoR) find next tabstop */
     for (i=curcol+1; (i<MAXCOL) && (tabstops[i]==0); i++);
     absmove(i,abslin);
}
 
line_feed()
{
/*    int tbot, ttop, tlout; */         /* (UoR) don't need these any more */
 
    if (newline) absmove(0,abslin);     /* (UoR) perform newline function */
 
    if (curlin == scrbot)
        scroll_up(scrtop,curlin);       /* (UoR) scroll lines up */
 
/*    {
        ScrollRect((Rect *) scrollrect,0,-LINEHEIGHT,dumptr);
        zeroline(scrtop);
        tbot = scrbot;
        ttop = scrtop;
        tlout = nxtlin[scrbot];
        nxtlin[scrbot] = scrtop;
        scrbot = scrtop;
        scrtop = nxtlin[scrtop];
        if (ttop == toplin) toplin = scrtop;
            else nxtlin[fndprv(ttop)] = scrtop;
        if (tbot == botlin)
        {
            botlin = scrbot;
            nxtlin[botlin] = -1;
        }
        else nxtlin[scrbot] = tlout;
        curlin = scrbot;
    } */                                /* (UoR) use Scroll_Up instead */
    else relmove(0,1);
}
 
reverse_line_feed()
{
/*    int tbot, ttop, tlout; */         /* don't need these any more */
 
    if (curlin == scrtop)
       scroll_down(curlin,scrbot);      /* (UoR) scroll down in region */
 
/*    {
        ScrollRect((Rect *) scrollrect,0,LINEHEIGHT,dumptr);
        zeroline(scrbot);
        tbot = scrbot;
        ttop = scrtop;
        tlout = nxtlin[scrbot];
        nxtlin[scrbot] = scrtop;
        scrtop = scrbot;
        scrbot = fndprv(scrbot);
        if (ttop == toplin) toplin = scrtop;
            else nxtlin[fndprv(ttop)] = scrtop;
        if (tbot == botlin)
        {
            botlin = scrbot;
            nxtlin[botlin] = -1;
        }
        else nxtlin[scrbot] = tlout;
        curlin = scrtop;
    } */                        /* (UoR) use scroll_down instead */
    else relmove(0,-1);
}
 
carriage_return()
{
    if (newline) line_feed();   /* (UoR) perform newline function */
       else absmove(0,abslin);
}
 
new_line()
{
    carriage_return();
    line_feed();
}
clear_screen()
{
    register int i;
    Rect r;
 
    makerect(&r,0,0,MAXLIN,MAXCOL);     /* The whole screen */
    EraseRect(&r);
 
    for (i=0; i<MAXLIN; i++) zeroline(i);   /* Clear up the update records */
}
 
home_cursor()
{
    if (relorigin) absmove(0,fndabs(scrtop));
       else absmove(0,0);       /* (UoR) correct for relative origin */
}
 
bell()
{
    SysBeep(3);
}
 
escape_seq()
{
    charflg = CF_SESC;                  /* Say we are in an escape sequence */
}
 
graphic_seq0()                          /* (UoR) do VT100 graphic characters */
{
    charflg = CF_GRF0;
}
graphic_seq1()
{
    charflg = CF_GRF1;
}
control_N()
{
    current_set = 1;    /* set to graphics set 1 */
}
control_O()
{
    current_set = 0;    /* set to graphics set 0 */
}
 
clear_line()
{
    int i;
    Rect r;
 
    switch (num1)
    {
        case 0:                         /* Clear:  here to the right */
            makerect(&r,abslin,curcol,1,MAXCOL-curcol);
            for (i=curcol; i<MAXCOL; i++) scr[curlin][i] = ' ';
            break;
 
        case 1:                         /* Clear:  left to here */
            makerect(&r,abslin,0,1,curcol+1);
            for (i=0; i<=curcol; i++) scr[curlin][i] = ' ';
            break;
 
        case 2:                         /* Clear:  entire line */
            makerect(&r,abslin,0,1,MAXCOL);
            zeroline(curlin);
            break;
    }
    EraseRect(&r);
}
 
erase_display()
{
    int i;
    Rect r;
 
    switch (num1)
    {
        case 0:
            clear_line();               /* Same num1 causes correct clear */
            makerect(&r,abslin+1,0,MAXLIN-abslin-1,MAXCOL); /* (UoR) -1 added */
            EraseRect(&r);
            for (i=abslin+1; i<MAXLIN; i++) zeroline(fndrel(i));
            break;
 
        case 1:
            clear_line();               /* Same num1 causes correct clear */
            makerect(&r,0,0,abslin,MAXCOL);
            EraseRect(&r);
            for (i=0; i<abslin; i++) zeroline(fndrel(i));
            break;
 
        case 2:
            clear_screen();
            break;
    }
}
 
/**** All cursor moves need to check that they don't go beyond the margins */
 
cursor_right()
{
    if (num1 == 0) num1 = 1;
    relmove(num1,0);
}
 
cursor_left()
{
    if (num1 == 0) num1 = 1;
    relmove(-num1,0);
}
 
cursor_up()
{
    int abstop;         /* (UoR) check that we don't pass scrtop */
 
    abstop = fndabs(scrtop);
    if (num1 == 0) num1 = 1;
    if ((abslin>=abstop) && (abslin-num1<abstop)) absmove(curcol,abstop);
       else relmove(0,-num1);
}
 
cursor_down()
{
    int absbot;         /* (UoR) check that we don't pass scrbot */
 
    absbot = fndabs(scrbot);
    if (num1 == 0) num1 = 1;
    if ((abslin<=absbot) && (abslin+num1>absbot)) absmove(curcol,absbot);
       else relmove(0,num1);
}
 
cursor_position()
{
/*    if (--num1 < 0) num1 = 0;
      if (--num2 < 0) num2 = 0;  */     /* This is taken care of by absmove */
 
      if (relorigin) absmove(--num2,fndabs(scrtop)+num1-1);     /* (UoR) */
          else absmove(--num2,--num1);  /* (UoR) moved "--" here from prev lines
 */
}
 
cursor_save()
{
    savcol = curcol;                    /* Save the current line and column */
    savlin = abslin;
 
    savsty = textstyle;                 /* (UoR) additions */
    savfnt = currentfont;
    savmod = invert;
    savgrf = current_set;
    savset[0] = graphicsinset[0];
    savset[1] = graphicsinset[1];
}
 
cursor_restore()
{
    absmove(savcol,savlin);             /* Move to the old cursor position */
 
    textstyle = savsty;                 /* (UoR) additions */
    currentfont = savfnt;
    invert = savmod;
    TextFont(currentfont);
    TextFace(textstyle);
    current_set = savgrf;
    graphicsinset[0] = savset[0];
    graphicsinset[1] = savset[1];
}
 
cursor_draw()
{
/*    Line(CHARWIDTH,0);*/                      /* Draw cursor */
 
    Rect r;
 
    if (cursor_invert == FALSE)
    {
        makerect(&r,abslin,curcol,1,1);         /* (UoR) Make Solid Cursor */
        r.left--;                               /* make r a little wider */
        r.top--;
        InvertRect(&r);
    }
    if (oldlin >= 0)                    /* (UoR) replace mouse cursor */
    {
        makerect(&r,oldlin,oldcol,1,1);
        r.left--;
        r.top--;
        PenMode(patXor);
        FrameRect(&r);
        PenMode(patCopy);
    }
    cursor_invert = TRUE;
    cursor_drawn = TRUE;
}
 
cursor_erase()
{
/*    Line(-CHARWIDTH,0);*/                     /* Erase cursor */
 
    Rect r;
 
    if (cursor_invert)
    {
        makerect(&r,abslin,curcol,1,1);         /* (UoR) Erase Solid Cursor */
        r.left--;                               /* make r a little wider */
        r.top--;
        InvertRect(&r);
    }
    if (oldlin >= 0)                    /* (UoR) remove mouse cursor */
    {
       makerect(&r,oldlin,oldcol,1,1);
       r.left--;
       r.top--;
       PenMode(patXor);
       FrameRect(&r);
       PenMode(patCopy);
    }
    cursor_invert = FALSE;
    cursor_drawn = FALSE;
}
 
flash_cursor(theWindow)
WindowPtr theWindow;
{
    Rect r;
 
    if (FrontWindow() != theWindow)
    {
        last_flash = TickCount();
        return;
    }
    if (((TickCount() - last_flash) > CARETTIME) ||
         (TickCount() - last_flash) < 0)
    {
        makerect(&r,abslin,curcol,1,1);
        r.top--;
        r.left--;
        last_flash = TickCount();
        if (cursor_drawn)
        {
            InvertRect(&r);
            if (cursor_invert) cursor_invert = FALSE;
                else cursor_invert = TRUE;
        }
    }
}
 
check_pointer(theWindow)
WindowPtr theWindow;
{
    int mouse_in_window, options_pressed, newlin, newcol;
    Point MousePt;
    KeyMap keyMask;     /* PACKED ARRAY [0..127] of BOOLEAN */
    Rect r;
 
    GetMouse(&MousePt);
    mouse_in_window = PtInRect(&MousePt,&ScreenRect);
    GetKeys(&keyMask);
    options_pressed = ((keyMask.kmap[1] & (long) 32772) == 32772);
 
    newlin = (MousePt.v - TOPMARGIN) / LINEHEIGHT;
    newcol = (MousePt.h - LEFTMARGIN) / CHARWIDTH;
 
    PenMode(patXor);    /* For FrameRect calls */
 
    if ((FrontWindow() == theWindow) &&
        (mouse_in_window) &&
        (options_pressed) &&
        (cursor_drawn))
    {
        if ((oldlin != newlin) || (oldcol != newcol))
        {
            if (oldlin >= 0)
            {
                makerect(&r,oldlin,oldcol,1,1);
                r.top--;
                r.left--;
                FrameRect(&r);
            }
/*          else HideCursor; */  /* Do this when we find HideCursor */
 
            makerect(&r,newlin,newcol,1,1);
            r.top--;
            r.left--;
            FrameRect(&r);
 
            oldlin = newlin;
            oldcol = newcol;
        }
        SetCursor(*mousecursor); /* Use blank cursor until we find HideCursor */
    }
 
    if ((FrontWindow() != theWindow) ||
        (mouse_in_window != TRUE) ||
        (options_pressed != TRUE) ||
        (cursor_drawn != TRUE))
    {
        if (oldlin >= 0)
        {
            makerect(&r,oldlin,oldcol,1,1);
            r.top--;
            r.left--;
            FrameRect(&r);
 
            oldlin = -1;
/*          ShowCursor;*/       /* when we find out where ShowCursor is */
        }
        SetCursor(&QD->arrow);
    }
 
    PenMode(patCopy);           /* reset to normal pen mode */
}
 
mouse_cursor_move(evt)
EventRecord *evt;
{
    int code, mouselin, mousecol, tempcol, templin, i;
    Point MousePt;
    register KSET *KS;
 
    code = evt->modifiers;
    code &= cmdKey + optionKey;
 
    KS = *kshdl;
 
    if (code == cmdKey + optionKey)
    {
        MousePt = evt->where;
        GlobalToLocal(&MousePt);
        mouselin = (MousePt.v - TOPMARGIN) / LINEHEIGHT;
        mousecol = (MousePt.h - LEFTMARGIN) / CHARWIDTH;
        tempcol = curcol;
        templin = abslin;
 
        if (mousecol < tempcol)
            for (i=tempcol; i>mousecol; i--)
            {
                writeps(getindstr(*(KS->fcnshdl), LEFTARROW+1));
                waitasec();
                        /* If tabs are used, we may go too far, so end loop */
                if (curcol <= mousecol) i = mousecol;
            }
        if (mouselin < templin)
            for (i=templin; i>mouselin; i--)
            {
               writeps(getindstr(*(KS->fcnshdl), UPARROW+1));
               waitasec();
            }
        else if (mouselin > templin)
            for (i=templin; i<mouselin; i++)
            {
               writeps(getindstr(*(KS->fcnshdl), DOWNARROW+1));
               waitasec();
            }
        if (abslin == mouselin) tempcol = curcol;       /* for short lines */
        if (tempcol < mousecol)
            for (i=tempcol; i<mousecol; i++)
            {
                writeps(getindstr(*(KS->fcnshdl), RIGHTARROW+1));
                waitasec();
                        /* If tabs are used, we may go too far, so end loop */
                if (curcol >= mousecol) i = mousecol;
            }
 
    }
}
 
waitasec()      /* (UoR) get any characters, and pause for a while */
{
    long end_time;
 
    end_time = TickCount() + 2;         /* pause for 1/30th second */
    while (TickCount() < end_time) ;
    inpchars();
}
 
 
 
 
 
 
 
 
 
set_scroll_region()
{
    if (--num1 < 0) num1 = 0;           /* Make top of line (prev line) */
    if (num2 == 0) num2 = 24;           /* Zero means entire screen */
 
    if (num1 < num2-1)          /* (UoR) make sure region is legal */
    {
           /* (UoR) remove scrollrect, since it is not used any more */
       topmargin = /*scrollrect[0] =*/ (num1 * LINEHEIGHT) + TOPMARGIN;
       bottommargin = /*scrollrect[2] =*/ (num2 * LINEHEIGHT) + TOPMARGIN;
 
       scrtop = fndrel(num1);
       scrbot = fndrel(num2-1);
 
       home_cursor();                   /* We're supposed to home it! */
    }
}
 
 
text_mode()                             /**** */
{
    switch(num1)
    {
        case 0:
            invert=FALSE;
            TextFont(VT100FONT);                /* (Uor) Use plain font */
            currentfont = VT100FONT;
            textstyle=0;
            TextFace(0);
/*          TextMode(srcOr);*/                  /* (UoR) always use XOR */
            break;
 
        case 1:
/*          textstyle +=boldStyle;
            TextFace(textstyle);  */   /* remove old bold algorithm (UoR) */
            TextFont(VT100BOLD);        /* use bold font instead */
            currentfont = VT100BOLD;
            break;
 
        case 4:
/*          textstyle+=underlineStyle; */  /* use = not += (avoid roll-over) */
            textstyle = underlineStyle;    /* (UoR) */
            TextFace(textstyle);
            break;
 
        case 5:                                 /* (UoR) blink is inverse */
        case 7:
            invert=TRUE;
/*          TextMode(srcBic);*/                 /* (UoR) always use XOR */
            break;
 
        case 21:
        case 22:
/*        if (textstyle >= boldStyle)
            {
                TextFace(textstyle-boldStyle);
                textstyle -= boldStyle;
            } */                       /* remove old bold algorithm (UoR) */
                TextFont(VT100FONT);       /* reset to plain font */
                currentfont = VT100FONT;
            break;
 
        case 24:
/*          if (textstyle >= underlineStyle)
            {
                TextFace(textstyle-underlineStyle);
                textstyle -= underlineStyle;
            } */                /* remove old method of underline (Uor) */
            TextFace(0);        /* just reset to plain style */
                                /* since bolding is done via a separate font */
            textstyle = 0;
            break;
 
        case 25:
        case 27:
            invert = FALSE;
/*          TextMode(srcOr);*/                  /* (UoR) always use XOR */
            break;
    }
}
 
 
 
 
 
 
 
 
 
/*
 * (UoR)
 *
 * Insert and Delete lines (replacements for originals, which have
 *   which have been deleted)
 *
 */
 
insert_line()
{
    int i,absbot;
 
    absbot = fndabs(scrbot);
 
    if ((abslin>=fndabs(scrtop)) && (abslin<=absbot))
    {
        if (num1 == 0) num1 = 1;
        if (num1 > absbot-abslin+1) num1 = absbot - abslin + 1;
 
        for (i=0; i<num1; i++) scroll_down(curlin,scrbot);
    }
}
 
delete_line()
{
    int i,absbot;
 
    absbot = fndabs(scrbot);
 
    if ((abslin>=fndabs(scrtop)) && (abslin<=absbot))
    {
        if (num1 == 0) num1 = 1;
        if (num1 > absbot-abslin+1) num1 = absbot - abslin + 1;
 
        for (i=0; i<num1; i++) scroll_up(curlin,scrbot);
    }
}
 
 
 
 
 
 
 
 
 
delete_char()
{
    int i;
    Rect r;
 
    if (num1 == 0) num1 = 1;
 
    makerect(&r,abslin,curcol,1,MAXCOL-curcol);
 
    if(num1 > MAXCOL - curcol - 1) num1 = MAXCOL - curcol - 1;
 
    ScrollRect(&r,-CHARWIDTH*num1,0,dumptr);  /* Scroll em out */
 
/* Shift em down */     /* (UoR) used to assign using abscol */
 
    for (i=curcol; i<MAXCOL-num1; i++) scr[curlin][i] = scr[curlin][i+num1];
    while (i < MAXCOL) scr[curlin][i++] = ' ';  /* Fill in holes with spaces */
}
 
insert_char()
{
    int i;
    Rect r;
 
    makerect(&r,abslin,curcol,1,MAXCOL-curcol);
 
    ScrollRect(&r,CHARWIDTH,0,dumptr);
 
/* Shift em up */       /* (UoR) used to assign ...[i-1]=...[i] */
                        /* (UoR) used to assign using abscol */
 
    for (i=MAXCOL-1; i>curcol; i--) scr[curlin][i] = scr[curlin][i-1];
    scr[curlin][curcol] = ' ';
}
 
insert_mode()
{
    if (prvchr == '?') set_mode();      /* (UoR) do some of these calls */
 
    switch(num1)
    {
        case 20:
            newline = TRUE;
            break;
 
        case 4:
            insert = TRUE;
            break;
    }
}
 
end_insert_mode()
{
    if (prvchr == '?') reset_mode();    /* (UoR) do some of these calls */
 
    switch(num1)
    {
        case 20:
            newline = FALSE;
            break;
 
        case 4:
            insert = FALSE;
            break;
    }
}
 
set_mode()
{
    Rect r;
 
    switch(num1)
    {
        case 5:
            if (screeninvert == FALSE)
            {
               BackPat(&QD->black);     /* (UoR) use black background */
               makerect(&r,0,0,MAXLIN,MAXCOL);
               InvertRect(&r);
               screeninvert = TRUE;
            }
            break;
 
        case 6:
            relorigin = TRUE;
            home_cursor();
            break;
 
        case 7:
            autowrap = TRUE;
            break;
 
        case 8:
            autorepeat = TRUE;
            break;
    }
}
 
reset_mode()
{
    Rect r;
 
    switch(num1)
    {
        case 5:
            if (screeninvert)
            {
               BackPat(&QD->white);
               makerect(&r,0,0,MAXLIN,MAXCOL);
               InvertRect(&r);
               screeninvert = FALSE;
            }
            break;
 
        case 6:
            relorigin = FALSE;
            home_cursor();
            break;
 
        case 7:
            autowrap = FALSE;
            break;
 
        case 8:
            autorepeat = FALSE;
            break;
    }
}
 
set_tab()
{
    tabstops[curcol] = 1;
}
 
clear_tab()
{
    int i;
 
    switch(num1)
    {
        case 0:
            tabstops[curcol] = 0;
            break;
 
        case 3:
            for (i=0; i<MAXCOL; i++) tabstops[i] = 0;
            break;
    }
}
 
 
 
 
 
 
 
 
 
writereply(s)           /* (UoR) use for respoding to information requests */
char *s;
{
    PLONG wrcnt, w2;
    int err; char *s2;
 
    w2 = wrcnt = strlen(s);     /* How long is the string? */
    for (s2 = s; w2 > 0; w2--,s2++) /* add parity */
      *s2 = dopar(*s2);
    err = FSWrite(outnum,&wrcnt,s);     /* Respond to the query */
    if (err) printerr("Bad Writeout:",err);
}
 
query_terminal()
{
    writereply(querystring);
}
 
request_report()                /* (UoR) reports */
{
    switch(num1)
    {
       case 5:          /* (UoR) report that we're OK */
         writereply(reportstring);
         break;
 
       case 6:          /* (UoR) reprt the cursor position */
         position_report();
         break;
 
       case 15:         /* (UoR) report printer status */
         if (prvchr == '?') writereply(noprinter);
         break;
    }
}
 
position_report()
{
    int i;
    char buf[9];
    char *report;
 
    i = 0;
    buf[i++] = '\033';
    buf[i++] = '[';
    if (abslin>9) buf[i++] = '0' + (abslin +1) / 10;
    buf[i++] = '0' + (abslin + 1) % 10;
    buf[i++] = ';';
    if (curcol>9) buf[i++] = '0' + (curcol + 1)/10;
    buf[i++] = '0' + (curcol + 1) % 10;
    buf[i++] = 'R';
    buf[i] = '\0';
    report = buf;
    writereply(report);
}
 
dummy()
{
}
 
multi_char()
{
    numone[0] = numtwo[0] = '0';        /* Initialize the numbers to zero */
    numone[1] = numtwo[1] = '\0';
    numptr = numone;                    /* Place to put the next number */
    prvchr = '\0';                      /* No priv char yet */
    charflg = CF_MESC;                  /* Say we are in a ESC [ swequence */
}
 
toss_char()
{
    charflg = CF_TOSS;
}
 
 
 
 
 
 
 
 
 
/*
 * Routine zeroline
 *
 * Zero (set to space) all the characters in relative line lin.
 *
 */
 
zeroline(lin)
int lin;
{
    register int i;
 
    for (i=0; i<MAXCOL; i++) scr[lin][i] = ' ';
}
 
/*
 * Move a relative number of lines and chars.  Both can be negative.
 *
 */
 
relmove(hor,ver)
{
/*    Move(hor*CHARWIDTH,ver*LINEHEIGHT);
    curcol += hor;
    abslin += ver;
    curlin = fndrel(abslin);*/  /* (UoR) remove old function */
 
    absmove(curcol+hor,abslin+ver);     /* (UoR) use absmove, which checks */
                                        /* for cursor moving off screen */
}
 
/*
 * Move to absolute position hor char and ver line.
 *
 */
 
absmove(hor,ver)
{
    if (hor>MAXCOL-1) hor = MAXCOL-1;   /* (UoR) make sure its on the screen */
    if (hor<0) hor = 0;
    if (ver>MAXLIN-1) ver = MAXLIN-1;
    if (ver<0) ver = 0;
    if (relorigin)
    {
        if (ver<fndabs(scrtop)) ver = fndabs(scrtop);
        if (ver>fndabs(scrbot)) ver = fndabs(scrbot);
    }
 
    MoveTo(hor*CHARWIDTH+LEFTMARGIN,(ver+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
    curcol = hor;
    abslin = ver;
    curlin = fndrel(ver);
}
 
 
 
 
 
 
 
 
 
/*
 * (UoR)
 *
 * Scroll lines within the scroll region upwards from line tlin
 * to line blin (lines are assumed to be in the region)
 *
 */
 
scroll_up(tlin,blin)
int tlin,blin;
{
   int newtop,abstop;
   Rect r;
 
   abstop = fndabs(tlin);
   makerect(&r,abstop,0,fndabs(blin) - abstop + 1,MAXCOL);
   ScrollRect(&r,0,-LINEHEIGHT,dumptr);
 
   if (tlin == blin)            /* if only one line, just clear it */
   {
       zeroline(blin);
       return;
   }
 
   newtop = nxtlin[tlin];                       /* new top line */
 
   if (tlin == scrtop) scrtop = newtop;         /* reset scrtop, if needed */
   if (tlin == toplin) toplin = newtop;         /* reset toplin, if needed */
     else nxtlin[fndprv(tlin)] = newtop;        /* else de-link tlin line */
 
   nxtlin[tlin] = nxtlin[blin];                 /* link tlin in after blin */
   nxtlin[blin] = tlin;
 
   if (blin == scrbot)          /* reset pointers to bottom of regions */
   {
      if (blin == botlin) botlin = tlin;
      scrbot = tlin;
   }
 
   zeroline(tlin);              /* clear the line */
   curlin = fndrel(abslin);
}
 
/*
 * (UoR)
 *
 * Scroll lines in scroll region down from line tlin to line blin
 * (lines are assumed to be within the scroll region)
 *
 */
 
 scroll_down(tlin,blin)
 int tlin,blin;
 {
     int abstop,newbot;
     Rect r;
 
     abstop = fndabs(tlin);
     makerect(&r,abstop,0,fndabs(blin)-abstop+1,MAXCOL);
     ScrollRect(&r,0,LINEHEIGHT,dumptr);
 
     if (tlin == blin)          /* if only one line, just clear it */
     {
        zeroline(tlin);
        return;
     }
 
     newbot = fndprv(blin);                     /* new bottom line */
 
     if (tlin == scrtop) scrtop = blin;         /* reset scrtop, if needed */
     if (tlin == toplin) toplin = blin;         /* reset toplin, if needed */
        else nxtlin[fndprv(tlin)] = blin;       /* else de-link top line */
 
     nxtlin[newbot] = nxtlin[blin];             /* link blin above tlin */
     nxtlin[blin] = tlin;
 
     if (blin == scrbot)        /* reset bottom of region pointers */
     {
        if (blin == botlin) botlin = newbot;
        scrbot = newbot;
     }
 
     zeroline(blin);
     curlin = fndrel(abslin);
}
 
 
 
 
 
 
 
 
 
/*
 * Find the relative line number given the absolute one.
 *
 */
 
fndrel(linum)
int linum;
{
    register int i, lin;
 
    lin = toplin;
    for (i=0; i<linum; i++) lin = nxtlin[lin];
    return(lin);
}
 
/*
 * Find the absolute line number given the relative one.
 *
 */
 
fndabs(linum)
int linum;
{
    int i, lin;
 
    lin = toplin;
    i = 0;
    while (lin != linum)
    {
        i++;
        lin = nxtlin[lin];
    }
    return(i);
}
 
/*
 * Find the previous relative line number from relative line linum.
 *
 */
 
fndprv(linum)
int linum;
{
    int lin;
 
    lin = toplin;
    while (nxtlin[lin] != linum) lin = nxtlin[lin];
    return(lin);
}
 
 
 
 
 
 
 
 
 
term_redraw()
{
    int i, lin;
    Rect r;
 
    lin = toplin;
    for (i=0; i<MAXLIN; i++)
    {
        MoveTo(LEFTMARGIN,(i+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
        if (screeninvert)       /* (UoR) refresh screen in invert mode */
        {
           makerect(&r,i,0,1,MAXCOL);
           EraseRect(&r);
        }
        DrawString(scr[lin]);
        lin = nxtlin[lin];
    }
    MoveTo(curcol*CHARWIDTH+LEFTMARGIN,
        (abslin+1)*LINEHEIGHT+TOPMARGIN-LINEADJ);
    if (cursor_drawn && cursor_invert)  /* (UoR) only if cursor is showing */
    {
        cursor_invert = FALSE;          /* (UoR) make sure we draw it */
        cursor_draw();                  /* redraw cursor */
        last_flash = TickCount();       /* (UoR) reset timer */
    }
}
 
init_term()
{
    int i;
 
    for (i=0; i<MAXLIN; i++)
    {
        nxtlin[i] = i + 1;              /* Tie together the linked list */
        scr[i][MAXCOL] = '\0';          /* Terminate the lines as strings */
    }
    toplin = 0;                         /* Initialize the top and bottom ptr */
    botlin = MAXLIN - 1;
    scrtop = toplin;                    /* Scrolling region equals all */
    scrbot = botlin;
    nxtlin[botlin] = -1;                /* Indicate this is the end */
    makerect (&ScreenRect,0,0,MAXLIN,MAXCOL);
                                        /* (UoR) full screen rectangle */
}
<<< ckmdef.h >>>
/* Symbol Definitions */
     
#define TRUE      1      		/* Boolean constants */
#define FALSE     0
#define NIL 	  0
#define NULL	  0
#define NILPTR	(Ptr) NIL
#define NILPROC (ProcPtr) NIL
#define VIS       1       		/* Sets window visisble */
#define ALLTYPES -1			/* All types for SFGetFile */
 
#define MYBUFSIZE   2048		/* Serial driver replacement buffer */
 
#define SCR_WREF 1			/* reference # for screen window */
#define TAB_WREF 2			/* # for the tabs window */
#define CTR_WREF 3			/* # for the control window */
#define RCD_WREF 4			/* remote command display window */
 
#define OKBtn	OK 			/* OK and Cancel constants */ 
#define QuitBtn	Cancel 			/* Defined by Dialog Mgr */
 
#define btnOff	0
#define btnOn	1
 
/* settings for parity */
 
#define MPARITY_ODD (oddParity+stop10+data7)
#define MPARITY_EVEN (evenParity+stop10+data7)
#define MPARITY_MARK (noParity+stop20+data7)
#define MPARITY_SPACE (noParity+stop10+data8)
#define MPARITY_NONE MPARITY_SPACE
 
#define KPARITY_ODD 'o'
#define KPARITY_EVEN 'e'
#define KPARITY_MARK 'm'
#define KPARITY_SPACE 's'
#define KPARITY_NONE 0
 
typedef unsigned char BOOL;		/* pascal boolean */
typedef int PLONG;			/* pascal long = cc68 int */
 
typedef struct {			/* file arguments since Kermit */
  char fillcl[64],filrem[64];		/*  doesn't pass all the info */
  int filflg;				/*  we need... */
  int fildflg;				/* default flags */
  short filvol;				/* file volume */
  int filfldr;				/* file folder for new files */
  PLONG filsiz;				/* size of file after open */
} FILINF;
 
/* Flags in filflg, fildflg */
 
#define FIL_BINA 1
#define FIL_TEXT 2
#define FIL_RSRC 4
#define FIL_DATA 8
#define FIL_OKILL 16			/* same as kermit's !warn */
#define FIL_DODLG 32			/* show dialogs on recv */
 
#define FIL_RBDT (FIL_RSRC | FIL_BINA | FIL_DATA | FIL_TEXT)
 
 
/* Globals Kermit variables */
 
extern char *cmarg,		/* pointer to cmd argument (file) */
      	    *cmarg2,		/* pointer to second cmd argument */
	    mypadc,		/* padding char to ask for */
	    padch,
	    eol,		/* end of line char to send */
	    seol,
	    mystch,		/* outbound packet start character */
	    stchr,
	    sstate;		/* kermit protocol state */
 
extern long
      	    ffc;		/* file character count  */
 
extern int speed,		/* speed of port */
      	   parity,		/* current parity setting */
	   duplex,		/* TRUE if full duplex */
	   binary,		/* TRUE if file mode is binary */
	   displa,		/* TRUE for calls to screen() */
	   bctr;		/* block check type (1, 2, or 3) */
	   delay,		/* initial delay before sending */
	   mypadn,		/* something to do with padding */
	   npad,
	   timint,		/* timeout interval in seconds */
	   rtimo,
	   spsiz,		/* max packet size we send */
	   rpsiz,
	   turnch,		/* line "turnaround" character */
	   turn,		/* if TRUE "turnaround" enabled */
	   quiet,		/* if TRUE screen() should be quiet */
	   nfils,		/*  */
	   warn,		/* TRUE does name conversion, else */
				/*   deletes duplicate names on recv */
	   server,    	  	/* TRUE if we are in server mode */
	   cxseen,		/* if TRUE abort file */
	   czseen;		/* if TRUE abort group */
 
/* Mac global variables */
 
extern int innum,			/* serial line input number */
      	   outnum;			/* serial line output number */
 
extern int protocmd;			/* current cmd that made us enter */
					/*  protocol or 0 if protocol is */
					/*  not running, or -1 if remote cmd */
extern FILINF filargs;			/* file information flags */
 
/* SYM for debugging, place at end of subroutine AFTER return */
 
#define SYM(x) { \
   asm("unlk a6"); \
   asm("rts"); \
   asm(".asciz 'x'"); \
   asm(".even"); }
 
 
 
<<< ckmfio.c >>>
/* Edit by Bill on Thu May 30, 00:18 */
/* Do error handling, neaten up comments, and some code. */
/* Edit by Bill on Wed May 15, 16:09 */
/* Make zrtol call common sfprtol, .RSRC overrides default settings */
/* ckmfio.c, Mon Apr 29 17:48, Edit by Bill*2 */
/* Put null in translated name to tie it off. */
/* Make author text of new file to ???? instead of random string */
/* Do flushvol after closing a file */
/* Bill C., Apr 24 */
/* Change zchin to allow sending of files with high order bits on */
/* Bill C., Apr 22 */
/* Add error handling (informing) for more cases, e.g. can't delete */
/* Bill C., Apr 22 */
/* Fix Resource/Data fork stuff.  Uppercase things where needed */
/* ckzmac.c, Thu Apr 21 17:19, Edit by Bill */
/*  Ignore trying to close an not-openend file, driver does it alot */
/* ckzmac.c, Thu Apr 11 21:18, Edit by Bill */
/*  Catch error in ZOPENO when trying to open an existing file */
/* ckzmac.c, Thu Apr 14 20:07, Edit by Bill */
/*  Translate calls with ZCTERM to go to the console routines */
 
/* 
 * File ckmfio  --  Kermit file system support for the Macintosh
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
/* Definitions of some Unix system commands */
 
char *DIRCMD = "";			/* For directory listing */
char *DELCMD = "";			/* For file deletion */
char *TYPCMD = "";			/* For typing a file */
char *SPACMD = "";			/* Space/quota of current directory */
char *SPACM2 = "";			/* For space in specified directory */
char *WHOCMD = "";			/* For seeing who's logged in */

/*
  Functions (n is one of the predefined file numbers from ckermi.h):
 
   zopeni(n,name)   -- Opens an existing file for input.
   zopeno(n,name)   -- Opens a new file for output.
   zclose(n)        -- Closes a file.
   zchin(n)         -- Gets the next character from an input file.
   zsout(n,s)       -- Write a null-terminated string to output file, buffered.
   zsoutl(n,s)      -- Like zsout, but appends a line terminator.
   zsoutx(n,s,x)    -- Write x characters to output file, unbuffered.
   zchout(n,c)      -- Add a character to an output file, unbuffered.
   zchki(name)      -- Check if named file exists and is readable, return size.
   zchko(name)      -- Check if named file can be created.
   znewn(name,s)    -- Make a new unique file name based on the given name.
   zdelet(name)     -- Delete the named file.
   zxpand(string)   -- Expands the given wildcard string into a list of files.
   znext(string)    -- Returns the next file from the list in "string".
   zxcmd(cmd)       -- Execute the command in a lower fork.
   zclosf()         -- Close input file associated with zxcmd()'s lower fork.
   zrtol(n1,n2)     -- Convert remote filename into local form.
   zltor(n1,n2)     -- Convert local filename into remote form.
 */

#include "ckcker.h"			/* Kermit definitions */
#include "ckmdef.h"			/* Common Mac module definitions */
#include "ckmres.h"			/* Resource defs */
#include "ckcdeb.h"			/* Debug() and tlog() defs */
#include <ctype.h>			/* Get islower and toupper */
#include "mac/quickdraw.h"
#include "mac/osintf.h"
#include "mac/toolintf.h"
 
/* These should all be settable by the File Settings Menu */
 
char  *authortext="????";		/* String to use as "author" of file */
 
#define FS_WIND 1			/* file is a text edit buffer */
#define FS_OPEN 2			/* file has been opened */
#define FS_RSRC 4			/*  opened in resource fork */
#define FS_DATA 8
#define FS_PIPE 16			/* file is a memory buffer */
 
typedef struct {
    PLONG frefnum;			/* file reference number (pascal) */
    int fstatus;			/* file status bits */
    char *fpipeptr;			/* pipe pointer */
} MACFILE;
 
MACFILE fp[ZNFILS] = { 			/* File information */
    {0,0},{0,0},{0,0},{0,0},
    {0,0},{0,0},{0,0}};
 
char pipebuf[128];			/* there's a limit to pipes! */
 

/*  Z O P E N I --  Open an existing file for input.  
 *
 * The file name has been returned from and the volume reference
 * number set by SFGetFile.
 *
 * Returns:
 *  TRUE: file opened ok
 *  FALSE: some error.
 */
 
zopeni(n,name)
int n;
char *name;
{
  int err;
  register MACFILE *fpp;
 
  if (chkfn(n)) {
    printerr("At zopeni file is already open ",n);
    return(FALSE);
  }
 
  fpp = &fp[n];
 
  if (n == ZCTERM) {			/* Terminal open? */
    if (chkfn(ZIFILE))			/* Check current ZOFILE */
      printerr("ZIFILE already open...: ",n);
    fp[ZIFILE].fstatus = FS_WIND;	/* redirect... here it is */
    fpp->fstatus = FS_WIND;		/* Indicate this is open too */
    return(conopen());			/* Return from low level open */
  }
    
  if (n == ZSYSFN)			/* trying to open a pipe? */
    return(zxcmd(name));		/* yes... */
     
  if (n == ZIFILE &&			/* opening input file? */
      (filargs.filflg & FIL_RSRC)) 	/*  and they said resource? */
    err = OpenRF(name,filargs.filvol,&fpp->frefnum);
  else					/* else some other channel or data */
    err = FSOpen(name,filargs.filvol,&fpp->frefnum);
 
  if (err != noErr)			/* check for open error */
    return(ioutil(err));		/* failed... */
 
  fpp->fstatus = FS_OPEN | (		/* set flags */
      	    (filargs.filflg & FIL_RSRC) ? FS_RSRC : FS_DATA);
 
  GetEOF(fpp->frefnum,&filargs.filsiz);  /* set size for screen */
  return(TRUE);				/* Return success */
  SYM(ZOPENI);
}
 

/*  Z O P E N O  --  Open a new file for output.
 *
 * Returns:
 *  TRUE: File opened ok
 *  FALSE: some error has occured or channel occupied.
 *
 */
 
zopeno(n,name)
int n;
char *name;
{
  int err;
  char *forktext;
  FInfo finfo;
  register MACFILE *fpp;
 
  if (chkfn(n)) {
    printerr("zopeno - file is already open: ",n);
    return(FALSE);
  }
 
  fpp = &fp[n];
 
  if (n == ZCTERM || n == ZSTDIO) {	/* Terminal open? */
    if (chkfn(ZOFILE))			/* Check current ZOFILE */
      printerr("ZOFILE already open...: ",n);
    fp[ZOFILE].fstatus = FS_WIND;	/* yes, redirect... here it is */
    fpp->fstatus = FS_WIND;		/* Indicate this is open too */
    return(conopen());			/* Return from low level open */
  }
    
  if (n == ZOFILE && (filargs.filflg & FIL_RSRC))
    forktext = "APPL";
  else
    forktext = "TEXT";			/* Make fork reflect fork choice */
 
  err = Create(name,filargs.filvol,authortext,forktext);
  if (err == dupFNErr) {		/* duplicate file? */
    if (!ioutil(FSDelete(name,		/* Try to delete it */
      	      	      filargs.filvol)))	/*  checking for failure */
      return(FALSE);			/* failed... */
    err = Create(name,filargs.filvol,	/* recreate */
      	      	  authortext,forktext); 
  }
  
  if (err != noErr)			/* some error? */
   return(ioutil(err));			/* yes, do message and return */
    
/* set file's folder from filargs.filfldr which is either the */
/* applications folder or the settings file folder */
 
  GetFInfo(name,filargs.filvol,&finfo); /* read current finder info */
  finfo.fdFldr = filargs.filfldr;	/* set new folder */
  SetFInfo(name,filargs.filvol,&finfo); /* and tell system about it */
 
  if (n == ZOFILE && 			/* is it our transferred file? */
      (filargs.filflg & FIL_RSRC))	/*  want to use resource fork?  */
    err = OpenRF(name,filargs.filvol,	/* yes... */
      	      	  &fpp->frefnum);
  else					/* else data, or some other file */
    err = FSOpen(name,filargs.filvol,
      	      	  &fpp->frefnum);
 
  if (err != noErr)			/* able to open? */
   return(ioutil(err));			/* no. fail return now */
   
  fp[n].fstatus = FS_OPEN | 
      ((filargs.filflg & FIL_RSRC) ? FS_RSRC : FS_DATA);
      
  return(TRUE);				/* done ok */
  SYM(ZOPENO);
}
 

/*  Z C L O S E  --  Close the given file.
 *
 * Returns:
 *  TRUE: file closed ok.
 *  FLASE: some error has occured.
 *
 */
 
zclose(n)
int n;
{
  int err = noErr;
  register MACFILE *fpp;
 
  if (!chkfn(n))			/* is it opened? */
    return(FALSE);			/* no return now */
 
  fpp = &fp[n];
 
  if (fpp->fstatus == FS_WIND)		/* is this a window? */
    fp[ZCTERM].fstatus = 0;		/* yes, clear ZCTERM */
  else
    if (fpp->fstatus == FS_PIPE)	/* is this a pipe? */
      fp[ZSYSFN].fstatus = 0;		/* yes, no pipe now, clear ZSYSFN */
    else {
      err = FSClose(fpp->frefnum);	/* else use OS close */
      if (err != noErr)			/* and if that worked */
        err = FlushVol(NILPTR,		/* flush buffers in case write */
	      filargs.filvol);	
    }
    
  fpp->fstatus = 0;			/* clear out status word */
  if (n == ZOFILE || n == ZIFILE)	/* turn off both flags */
      filargs.filflg &= ~(FIL_RSRC | FIL_DATA);
 
  return(ioutil(err));			/* return according to io operations */
  SYM(ZCLOSE);
}
 

/*  Z C H I N  --  Get a character from the input file.
 *
 * Returns:
 *  0: Ok
 * -1: EOF (or other error).
 *
 */
 
zchin(n,c)
int n;
char *c;
{
  int err;
  PLONG rdcnt;				/* pascal long */
  register MACFILE *fpp;
 
  if (!chkfn(n))
    return(0);
 
  fpp = &fp[n];
 
  if (fpp->fstatus == FS_WIND) {	/* a window? */
    printerr("zchin called for FS_WIND file: ",n);
    return(0);
  }
    
  if (fpp->fstatus == FS_PIPE)		/* a pipe? */
    if (*(fpp->fpipeptr) == '\0')	/* is this eo-pipe? */
      return(-1);			/* yes, fail return */
    else {
      *c = *(fpp->fpipeptr)++;		/* read character */
      return(0);			/* success */
    }
      
  rdcnt = 1;
  err = FSRead(fpp->frefnum,&rdcnt,c);
  if (err == eofErr) return(-1);	/* Failure return */
  return(ioutil(err) ? 0 : -1);		/* success or unknown failure */
  SYM(ZCHIN);
}

/*  Z S O U T  --  Write a string to the given file, buffered.
 *
 * Returns:
 *  0: OK
 * -1: Error
 *
 */ 
 
zsout(n,s)
int n;
char *s;
{
  PLONG wrcnt;				/* pascal long */
 
  if (n == ZCTERM || fp[n].fstatus == FS_WIND)
    return(conol(s));
    
  wrcnt = (long) strlen(s);
  return(ioutil(FSWrite(fp[n].frefnum,&wrcnt,s)) ? 0 : -1);
  SYM(ZSOUT);
}
 
/*  Z S O U T L  --  Write string to file, with line terminator, buffered.
 *
 * Returns:
 *  0: OK
 * -1: Error
 *
 */
 
zsoutl(n,s)
int n;
char *s;
{
  PLONG wrcnt;			/* pascal long */
  int err;
 
  if (n == ZCTERM || fp[n].fstatus == FS_WIND)
    return(conoll(s));
     
  wrcnt = (long) strlen(s);
  err = FSWrite(fp[n].frefnum,&wrcnt,s);
  if (err == noErr) {
    wrcnt = 2;
    err = FSWrite(fp[n].frefnum,&wrcnt,"\r\n");
  }
  
  return(ioutil(err) ? 0 : -1);
  SYM(ZSOUTL);
}
 
/*  Z S O U T X  --  Write x characters to file, unbuffered.
 *
 * Returns:
 *  0: OK
 * -1: Error
 */
 
zsoutx(n,s,x)
int n, x;
char *s;
{
  if (n == ZCTERM || fp[n].fstatus == FS_WIND)
    return(conxo(s,x));
    
  return(ioutil(FSWrite(fp[n].frefnum,(PLONG *) &x,s)) ? 0 : -1);
  SYM(ZSOUTX);
}
 
 
/*  Z C H O U T  --  Add a character to the given file.
 *
 * Returns:
 *  0: OK
 * -1: Error
 */
 
zchout(n,c)
int n;
char c;
{
  PLONG wrcnt;				/* pascal long */
  int err;
 
  if (n == ZCTERM || fp[n].fstatus == FS_WIND)
    return(conoc(c));			/* Then send to console routine */
     
  wrcnt = 1;
  err = FSWrite(fp[n].frefnum,&wrcnt,&c);
  if (err != noErr)			/* error occured? */
    sstate = 'a';			/* yes, abort protocol */
  return (ioutil(err) ? 0 : -1);	/* else return code */
  SYM(ZCOUT);
}

/*  C H K F N  --  Internal function to verify file number is ok.
 *
 * Returns:
 *   TRUE  - file is open
 *  FALSE  - file is not open
 * 
 * Issues an error message if the file number is not in range.
 *
 */
 
chkfn(n)
int n;
{
  switch (n) {
    case ZCTERM:
    case ZSTDIO:
    case ZIFILE:
    case ZOFILE:
    case ZDFILE:
    case ZTFILE:
    case ZPFILE:
    case ZSYSFN:
    case ZSFILE: break;
    default:
      debug(F101,"chkfn: file number out of range","",n);
      printerr("chkfn - file number not in range: ",n);
      return(FALSE);			/* ugh */
  }
  return((fp[n].fstatus != 0));		/* if open, fstatus is nonzero */
  SYM(CHKFN);
}

/*  Z C H K I  --  Check if input file exists and is readable.
 *
 * Returns:
 *  >= 0 if the file can be read (returns the size).
 *    -1 if file doesn't exist or can't be accessed,
 *    -2 if file exists but is not readable (e.g. a directory file).
 *    -3 if file exists but protected against read access.
 */
 
zchki(name)
char *name;
{
  PLONG size;
  int err;
  FileParam info;
 
  if (strcmp(name,"stdin") == 0)	/* stdin is a pipe */
   return(strlen(pipebuf));		/* return size of buffer */
 
  c2pstr(name);				/* convert to a pascal string */
  info.ioFVersNum = 0;			/* No version number */  
  info.ioFDirIndex = 0;			/* Use the file name */
  info.ioNamePtr = name;		/* Point to the file name */
  info.ioVRefNum = filargs.filvol;	/* Volume number */
  err = PBGetFInfo(&info,FALSE);	/* Get info on file */
  p2cstr(name);				/* put the name back */
  
  if (err == fnfErr)			/* file not found? */
    return(-1);				/* then that is what they want */
    
  if (err != noErr)			/* any other error? */
    printerr("zchki failed: ",err);  	/* tell me about it */
 
  size = (filargs.filflg & FIL_RSRC) ?	/* if thinking about RSRC */
      	info.ioFlRPyLen : info.ioFlPyLen; /*  return that size, else DATA */
  return(size);				/* did ok */
  SYM(ZCHKI);
}

/*  Z C H K O  --  Check if output file can be created.
 *
 * Returns
 *  0: Write OK
 * -1: write permission for the file should be denied.
 */
 
zchko(name)
char *name;
{
  char volname[100];
  VolumeParam info;
 
  info.ioVolIndex = 0;			/* Use the vol ref num only */
  info.ioNamePtr = volname;		/* Pointer to the volume name */
  info.ioVRefNum = filargs.filvol;	/* Volume reference number */
  if (!ioutil(PBGetVInfo(&info,0)))	/* Get info on vol, synchronously */
    return(-1);				/* failed... */
 
  if ((info.ioVAtrb & 0x8000) != 0)	/* Write locked? */
    return(-1);				/* yes... */
    
  return(0);				/* else success */
  SYM(ZCHKO);
}

/*  Z D E L E T  --  Delete the named file.  */
 
zdelet(name)
char *name;
{
  int err;
  err = FSDelete(name,filargs.filvol);
  if (err != fnfErr && err != noErr)	/* file not found... I guess thats */
    return(ioutil(err));		/*  ok... */
  return(TRUE);				/* well done */
  SYM(ZDELETE);
}
 
 
/*  Z R T O L  --  Convert remote filename into local form.
 *
 * Check here to see if this should go into the resource fork (.rsrc)
 * or into the data fork (.data).
 *
 */ 
 
zrtol(name,name2)
char *name, *name2;
{
  
  strcpy(name2,name);			/* copy name to destination */
    
  if (filargs.filflg & (FIL_DODLG))	/* selected by user? */
    return;				/* won't be called but... */
 
  filargs.filflg &= ~(FIL_RBDT);	/* clear out flags */
  filargs.filflg |= sfprtol(name2);	/* convert name2 and set flags */
  binary = (filargs.filflg & FIL_BINA); /* selected binary mode? */  
  return;
  SYM(ZRTOL);
}
 
 
/*  Z L T O R  --  Convert filename from local format to common form. */
 
zltor(name,name2)
char *name, *name2;
{
  int dc = 0;
 
  while (*name != '\0') {
    if (*name == ' ') 
      name++;				/* Skip spaces */
    else
      if ((*name == '.') && (++dc > 1)) {
	*name2++ = 'X'; 		/* Just 1 dot */
	name++;
      }
      else 
      	*name2++ = (islower(*name)) ? toupper(*name++) : *name++;
  }
  *name2++ = '\0';			/* deposit final null */
  return;
  SYM(ZLTOR);
}    
 
 
/*  Z C H D I R  --  Change directory  (used on the Mac to switch vols) */
 
zchdir(dirnam)
char *dirnam;
{
  int err;
 
  err = SetVol(dirnam,0);		/* set default volume */
  if (err == noErr)
  {
   screen(SCR_TN,0,0l,dirnam);
   filargs.filvol = 0;			/* make default */
  }
  else
   screen(SCR_TN,0,0l,"Can't set volume");
 
  return(err == noErr);			/* return ok or fail */
  SYM(ZCHDIR);
}
 

/*  Z X C M D -- Run a system command so its output can be read like a file.
 *
 * Used on the MAC to implement MAC settings commands -- commands from a
 * remote system when in server mode that change internal variables.
 *
 */
 
#define CMD_RSRC 1
#define CMD_DATA 2
#define CMD_TEXT 3
#define CMD_BINA 4
#define CMD_UNK 255
 
zxcmd(comand)
char *comand;
{
  int sc;
 
  fp[ZIFILE].fstatus = FS_PIPE;		/* set input from pipe */
  fp[ZIFILE].fpipeptr = pipebuf;	/* init pointer to buffer */      
 
  switch (sc = getcmd(comand)) {
    case CMD_RSRC:
    case CMD_DATA:
      strcpy(pipebuf,"Default Fork set OK\n");
      filargs.filflg &= ~(FIL_RSRC | FIL_DATA); /* turn off  */
      filargs.filflg |= (sc == CMD_RSRC) ? FIL_RSRC : FIL_DATA;
      return(TRUE);			/* success */
 
    case CMD_TEXT:
    case CMD_BINA:
      strcpy(pipebuf,"Default Mode set OK\n");
      filargs.filflg &= ~(FIL_TEXT | FIL_BINA);
      filargs.filflg |= (sc == CMD_BINA) ? FIL_BINA : FIL_TEXT;
      return(TRUE);			/* ok */
      
    default:
      return(FALSE);			/* fail, unknown */
  }    
  SYM(ZXCMD);
}
 
char *cmdtab[] = {
  "fork rsrc",
  "fork data",
  "mode binary",
  "mode text"
};
 
int toktab[] = {
  CMD_RSRC,
  CMD_DATA,
  CMD_BINA,
  CMD_TEXT
};
 
#define NTOKS (sizeof (toktab)/sizeof(int))
 
getcmd(cmd)
char *cmd;
{
  int k;
 
  for (k=0; k < NTOKS; k++)
   if (strcmp(cmdtab[k],cmd) == 0)
    return(toktab[k]);			/* and return ID */
  return(CMD_UNK);			/* else unknown */
  SYM(GETCMD);
}
 

 
/*  Z C L O S F  - wait for the child fork to terminate and close the pipe. */
 
zclosf() 
{
  return;
}
 

int znfirst = 0;
char *zname;
 
/*  Z X P A N D  --  Expand a wildcard string into an array of strings
 *
 * Returns the number of files that match fn1, with data structures set up
 * so that first file (if any) will be returned by the next znext() call.
 */
 
zxpand(fn)
char *fn;
{
  znfirst = 0;				/* Say this is the first time thru */
  zname = fn;				/* Save a pointer to that name */
  return(1);				/* Say one file matches */
  SYM(ZXPAND);
}
 
/*  Z N E X T  --  Get name of next file from list created by zxpand().
 *
 * Returns >0 if there's another file, with its name copied into the 
 * arg string, or 0 if no more files in list.
 */
 
znext(fn)
char *fn;
{
  if (znfirst++ == 0) {
    strcpy(fn,zname);			/* Get the file's name */
    return(1);				/* No more files in this wildcard */
  }
  else return(0);
  SYM(ZNEXT);
}
 
/*  Z N E W N  --  Make a new name for the given file  */
 
znewn(fn,s)
char *fn, **s;
{
  char *extp;
  int ver;
 
  strcpy(*s,fn);			/* copy in the name */
  if (strlen(*s) > 59)			/* don't allow long names */
   *s[59] = '\0';			/* it breaks the finder */
  extp = *s+strlen(*s);			/* find position of extension */
  *extp++ = '.';			/* add in the dot now */
  
  for (ver=0; ver < 99; ver++)		/* I'll try this many names */
  {
    NumToString(ver,extp);		/* add in the number */
    if (zchki(*s) == -1)		/* is this file known? */
     return;				/* no, made a good one! */
  }
  fatal("znewn failed to find unique name in 64 attempts",0);
  return;
  SYM(ZNEWN);
}
 
/* zkself() - Kill self (reboot).  On other machines does a logout.
 *    	      Flush volumes and reboot.  Called by remote BYE.
 *
 */
 
zkself()
{
  DrvQEl *drvqe;
  char vname[255];
  PLONG vfreeb;
  int vrefnum,err;
 
  for (drvqe = (DrvQEl *) DrvQHdr->qHead; /* handle on drive q */
       drvqe != NULL;			/* while still something */
       drvqe = drvqe->qLink)		/* step to next */
  {					/* for each drive */
    err = GetVInfo(drvqe->dQDrive,vname,&vrefnum,&vfreeb);
    if (err = noErr)
      err = FlushVol(NILPTR,vrefnum);	/* flush the volume given refnum */
    else
     if (err != nsvErr)
       screen(SCR_TN,0,0l,"Remote cmd: GetVinfo returned unknown code");
  }    
  asm("	reset");			/* reset the machine */
  asm("	jmp /40000A");			/* boot address */
  return(FALSE);
  SYM(ZKSELF);
}

 
/* ioutil - handle the result from an IO call, checking for an
 *    	    error return and displaying an appropriate error
 *    	    message.  Returns TRUE if no error occured, FALSE
 *    	    otherwise.
 */
 
struct {
  int errnum;
  char *errstr;
} ioerrs[] = {
    {dirFulErr,"Directory is full"},
    {dskFulErr,"Disk is full"},
    {wPrErr,"Diskette is write protected"},
    {fLckdErr,"File is software locked"},
    {vLckdErr,"Volume is software locked"},
    {fBsyErr,"File is busy"},
    {opWrErr,"File is already open with write permission"},
    {0,NILPTR}
  };
 
ioutil(err)
int err;
{
  int e;
 
  if (err == noErr)
   return(TRUE);
 
  for (e = 0; ioerrs[e].errnum != 0 && 
      	      ioerrs[e].errnum != err; e++);
 
  if (ioerrs[e].errstr == NILPTR)	/* anything there? */
   printerr("Unknown IO error: ",err);
  else
   printerr(ioerrs[e].errstr,0);
   
  return(FALSE);   
  SYM(IOUTIL);
}
<<< ckmke2.c >>>
/*
 * CKMKE2.C
 *
 * Key-Config is a keyboard configurator program for use with Columbia's
 * MacKermit.
 *
 * Bill Schilit, April 1985
 *
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#include "mac/quickdraw.h"		/* order does matter */
#include "mac/osintf.h"			/*  on these... */
#include "mac/toolintf.h"
#include "mac/packintf.h"
#include "ckmkey.h"
#include "ckmkkc.h"
#include <ctype.h>
 
Rect kbbox,smallbox;
 
int keymods = 0,			/* current modifiers from keyboard  */
    butmods = 0,			/* current modifiers from button */
    keysel = KC_NUN,			/* selected key */
    kbselected = TRUE;			/* kb or text is active */
 
struct KEYCODE {
  int kcode;				/* key code */
  int krow;				/* row and column on keyboard */
  int kcol;
  int ksize;				/* horizontal key size */
  int khpos;				/* horizontal position */
  char *kname;				/* key name */
  Rect krect;
} keycodes[] = {
  {0x32,1,1,R1,0,"`"},{0x12,1,2,R1,R1,"1"},     	    /* `1 */
  {0x13,1,3,R1,2*R1,"2"},{0x14,1,4,R1,3*R1,"3"},	    /* 23 */
  {0x15,1,5,R1,4*R1,"4"},{0x17,1,6,R1,5*R1,"5"}, 	    /* 45 */
  {0x16,1,7,R1,6*R1,"6"},{0x1A,1,8,R1,7*R1,"7"},	    /* 67 */
  {0x1C,1,9,R1,8*R1,"8"},{0x19,1,10,R1,9*R1,"9"},     	    /* 89 */
  {0x1D,1,11,R1,10*R1,"0"},{0x1B,1,12,R1,11*R1,"-"}, 	    /* 0- */
  {0x18,1,13,R1,12*R1,"="},{0x33,1,14,R2,13*R1,"Backspace"}, /* =<BS> */
 
  {0x30,2,1,R2,0,"Tab"},{0x0C,2,2,R1,R2,"Q"},	    	    /* <TAB>Q */
  {0x0D,2,3,R1,R1+R2,"W"},{0x0E,2,4,R1,2*R1+R2,"E"},	    /* WE */
  {0x0F,2,5,R1,3*R1+R2,"R"},{0x11,2,6,R1,4*R1+R2,"T"},      /* RT */
  {0x10,2,7,R1,5*R1+R2,"Y"},{0x20,2,8,R1,6*R1+R2,"U"},      /* YU */
  {0x22,2,9,R1,7*R1+R2,"I"},{0x1F,2,10,R1,8*R1+R2,"O"},	    /* IO */
  {0x23,2,11,R1,9*R1+R2,"P"},{0x21,2,12,R1,10*R1+R2,"["},   /* P[ */
  {0x1E,2,13,R1,11*R1+R2,"]"},{0x2A,2,14,R1,12*R1+R2,"\\"},  /* ]\ */
 
  {KC_KLK,3,1,R3,0,"Caps lock"},			    /* <CAPS LOCK> */
  {0x00,3,2,R1,R3,"A"},{0x01,3,3,R1,R1+R3,"S"},		    /* AS */
  {0x02,3,4,R1,2*R1+R3,"D"},{0x03,3,5,R1,3*R1+R3,"F"},	    /* DF */
  {0x05,3,6,R1,4*R1+R3,"G"},{0x04,3,7,R1,5*R1+R3,"H"},      /* GH */
  {0x26,3,8,R1,6*R1+R3,"J"},{0x28,3,9,R1,7*R1+R3,"K"},      /* JK */
  {0x25,3,10,R1,8*R1+R3,"L"},{0x29,3,11,R1,9*R1+R3,";"},    /* L; */
  {0x27,3,12,R1,10*R1+R3,"'"},{0x24,3,13,R3,11*R1+R3,"Return"},  /* '<RET> */
 
  {KC_SHF,4,1,R4,0,"Shift"},				    /* <SHIFT> */
  {0x06,4,2,R1,R4,"Z"},{0x07,4,3,R1,R1+R4,"X"},  	    /* ZX */
  {0x08,4,4,R1,2*R1+R4,"C"},{0x09,4,5,R1,3*R1+R4,"V"},	    /* CV */
  {0x0B,4,6,R1,4*R1+R4,"B"},{0x2D,4,7,R1,5*R1+R4,"N"},      /* BN */
  {0x2E,4,8,R1,6*R1+R4,"M"},{0x2B,4,9,R1,7*R1+R4,","},      /* M, */
  {0x2F,4,10,R1,8*R1+R4,"."},{0x2C,4,11,R1,9*R1+R4,"/"},    /* ./ */
  {KC_SHF,4,12,R4,10*R1+R4,"Shift"},		 	    /* <SHIFT> */
  
  {KC_OPT,5,1,R1,R1,"Option"},				    /* <OPTION> */
  {KC_CMD,5,2,R2,2*R1,"Command"},			    /* <CMD> */
  {0x31,5,3,R5,2*R1+R2,"Space"},			    /* <SPACE> */
  {0x34,5,4,R2,2*R1+R2+R5,"Enter"},   			    /* <ENTER> */
  {KC_OPT,5,5,R1,2*R1+2*R2+R5,"Option"}			    /* <OPTION> */
};
 
#define NKEYS (sizeof(keycodes)/sizeof(struct KEYCODE))
 
Rect scoderects[MAX_SCODE+1];		/* rectanges for scan codes */
 

/* myfilter - filter events */
 
myfilter()
{
  struct {
    short *itemhit;			/* (in stack order) */
    EventRecord *theevent;    
    DialogPtr thedialog;
  } args;
  char *retval; 
  int newmods,
      newkey = KC_NUN;
  Point localpt;
 
  retval = (char *) getpargs(&args,sizeof(args));
  *retval = FALSE;			/* modal can deal with it */   
 
/* check for events which we do updates on */
 
  newmods = keymapmods();		/* set from modifiers from key map */
 
  switch (args.theevent->what) {
    
    case mouseDown:			/* check for mouse in KB */
      localpt = args.theevent->where;	/* copy the point */
      GlobalToLocal(&localpt);		/* make it local */  
      if (PtInRect(&localpt,&kbbox))	/* in our KB picture? */
	newkey = mousekb(&localpt,	/* yes set butmod and newkey */   
	      args.theevent->when); 	
      break;
 
    case keyDown:			/* key down event */
      if (kbselected)			/* do we want to handle it? */
      {					/* yes, KB is selected */
	*retval = TRUE;			/* so do not let modal do it */
	*args.itemhit = SETKD_KEYB;	/* ... */
	newmods = 			/* get key modifiers */       
	    args.theevent->modifiers & 
	    (alphaLock | cmdKey | optionKey | shiftKey);
	newkey = (args.theevent->message & keyCodeMask) >> 8;  /* and key */
      }
      break;
  }    
 
  newmods |= butmods;			/* include those set by button */
 
/* check for ambigous key stroke */
 
  if ((newmods & (*kshdl)->ctrlmods) &&	/* both ctrl and */
      (newmods & (*kshdl)->caplmods))	/*  caps lock? */
  { 
   SysBeep(1);				/* yes... */
   butmods = 0;				/* clear these out */
   *args.itemhit = 0;			/* ignore it... */
   return;				/* ugh */
  }
  
  if (keymods != newmods)		/* change in modifiers? */
  {
    keymods = newmods;			/* set new mod flags */
    drawkeychars(keymods);		/* do update on character set */
    hilitemods(keymods);		/* draw highlighted mod keys */
    if (keysel != KC_NUN)		/* something to keep hi-lited? */
     hilitekey(keysel);			/* yes... do it */
  }
 
  if (newkey != keysel && 		/* change in selected key? */
      newkey != KC_NUN)			/* and something selected? */
  {
    if (keysel != KC_NUN)		/* was there a previous? */
     hilitekey(keysel);			/* yes, so de-hilite it */
    keysel = newkey;			/* set current key */
    if (keysel != KC_NUN)		/* selected something good? */
     hilitekey(keysel);			/* yes, so hilite it */
  }
}
 

long lastwhen = 0;
int lastkeyc = KC_NUN;
 
 
/* mousekb - mouse down occured inside our KB item */
 
mousekb(pt,when)
Point *pt;
long when;
{
  int doubletime,
      twoclick,
      keyc = KC_NUN,
      modv;
  int k;
  
  doubletime = (SysPPtr->volClik >> 4) & 0x0f;
  doubletime *= 4;
  twoclick = ((when - lastwhen) <= doubletime);
  lastwhen = when;			/* remember last time */
  
  for (k = 0; k<NKEYS; k++)
    if (PtInRect(pt,&keycodes[k].krect)) /* found the KB key? */
    {
     keyc = keycodes[k].kcode;		/* here is the key code */
     break;				/* yes, it's in k */
    }
 
  if (keyc == KC_NUN)			/* not inside a key */
  {
    SysBeep(1);
    return(KC_NUN);
  }
  
  if (twoclick && (lastkeyc == keyc))	/* double click on it? */
   switch (keyc)			/* yes... maybe enter dlog */
   {
     case KC_CMD:
     case KC_SHF:
     case KC_KLK:
     case KC_OPT:
       dosetmkdialog();			/* enter the setup dialog */
       InvalRect(&kbbox);		/* cause entire update */
       return(KC_NUN);
     default:
       SysBeep(1);			/* can't open others */
       return(KC_NUN);
   }
 
   lastkeyc = keyc;			/* remember the key */   
   modv = keycodemods(keyc);		/* get modifier value if any */
   if (modv == 0)
    return(keyc);			/* return the key */
   butmods ^= modv;			/* toggle the button modifiers */
   return(KC_NUN);
}
 
 
initkeyrects()
{
  int k;
  Rect *kr;
 
  for (k=0; k < NKEYS; k++)
  {
    kr = &scoderects[keycodes[k].kcode];
    keyrect(&keycodes[k],kr,0);
    keyrect(&keycodes[k],&keycodes[k].krect,3);
  }
}
    
keyrect(k,kr,inset)
struct KEYCODE *k;
Rect *kr;
{
 SetRect(kr,0,0,k->ksize,K_HEIGHT);	    /* form key size */
 OffsetRect(kr,k->khpos,(k->krow-1)*K_HEIGHT); /* offset */
 InsetRect(kr,inset,inset);		/* make it fit per caller var */
 OffsetRect(kr,kbbox.left,kbbox.top); 	/* offset to our region */
} 
 

/* keymapmods */
 
#define KM_CMD 0x8000			/* KeyMap bit for cmdKey */
#define KM_SHF 0x1			/* KeyMap bit for shiftKey */
#define KM_KLK 0x2			/* KeyMap bit for alphaLock */
#define KM_OPT 0x4			/* KeyMap bit for optionKey */
 
int keymapmods() 
{
  KeyMap km;
  register int mods;
  register long kmw2;
 
  GetKeys(&km);
  mods = 0;  
  kmw2 = km.kmap[1];			/* all bits are in second word */
  if (kmw2 & KM_SHF) 
    mods |= shiftKey;
  if (kmw2 & KM_OPT) 
    mods |= optionKey;
  if (kmw2 & KM_CMD) 
    mods |= cmdKey;
  if (kmw2 & KM_KLK) 
    mods |= alphaLock;
  return(mods);
}
 

drawkeychars(mods)
{
  FontInfo fi;  
  char *kn,*namekey(),*namefkey();
  BOOL ismeta,isfkey;
  int k,vs,hs,kval;
  Rect *kr;
 
  TextFont(geneva);			/* has ok 9 pt system font */
  TextSize(9);				/* small font */
  GetFontInfo(&fi);			/* info for descent+ascent */
  
  vs = (fi.descent+fi.ascent-K_HEIGHT)/2; /* vertical space for centering */
 
  for (k=0; k<NKEYS; k++)
  {
    kr = &keycodes[k].krect;
    EraseRect(kr);			/* clean out old value */
    TextFace(boldStyle);      
    switch (keycodes[k].kcode)
    {
      case KC_CMD: kn = "Cmd"; break;	/* apple key */
      case KC_OPT: kn = "Opt"; break;
      case KC_SHF: kn = "Shift"; break;
      case KC_KLK: kn = "Cap Lock"; break;
      default:
      	kval = mapkey(keycodes[k].kcode,mods,&ismeta,&isfkey);
	if (!isfkey)			/* is it a function key? */
	 TextFace(0);			/* no, use normal font */
      	kn = namekey(kval,ismeta,isfkey,FALSE); /* give it a name */
	break;
    }
    hs = (keycodes[k].ksize - StringWidth(kn))/2; /* leading space */
    MoveTo(kr->left+hs-2,kr->bottom+vs); /* position the pen */
    DrawString(kn);				  /* draw it */
  }
  TextSize(0);				/* back to default */
  TextFace(0);
  TextFont(0);
}
 
PicHandle kbpic = NULL;
 
drawkeyboard(r)
Rect *r;
{
  int k;
  Rect kr;
 
  if (kbpic == NULL)
  {
    kbpic = OpenPicture(&kbbox);	/* open a picture */
    for (k=0; k<NKEYS; k++)		/* for all keys */
    {
      keyrect(&keycodes[k],&kr,1);
      FrameRoundRect(&kr,6,6);
    }
    ClosePicture();			/* all done */
  }
  HLock((Handle) kbpic);
  DrawPicture(kbpic,r);			/* draw the picture */
  HUnlock((Handle) kbpic);
}
 
hilitekey(kcode)
int kcode;
{
 int k;
 Rect kr;
 
 for (k=0; k<NKEYS; k++)
  if (keycodes[k].kcode == kcode)
  {
    keyrect(&keycodes[k],&kr,3);
    InvertRect(&kr);
    if (keycodes[k].kcode != KC_SHF &&	/* want to hilite another? */
      	keycodes[k].kcode != KC_OPT)	/* shift and option are two keys */
    return;
  }
}
 
hilitemods(mods)
{
 if (mods & optionKey)
   hilitekey(KC_OPT);
 if (mods & cmdKey)
   hilitekey(KC_CMD);
 if (mods & alphaLock)
   hilitekey(KC_KLK);
 if (mods & shiftKey)
   hilitekey(KC_SHF);
}
 
/* namekey - Given an 8 bit character value returns a string containing
 *    	     the name for the key. If lform is TRUE names are returned as:
 *
 *    	      Control-Meta-X, or Control-X, or X
 *
 *    	     if lform is FALSE, names are returned in the shorter form:
 *
 *    	      C-M-X, or C-X, or X.
 */
 
char *namekey(key,ismeta,isfkey,lform)
CHAR key;
BOOL ismeta,isfkey;
int lform;
{
  static char keyname[100];
  char *keyp = keyname,
       keyc[2];
 
  keyname[0] = keyc[1] = 0;		/* start with empty strings */
 
  if (isfkey) {				/* is this a function def? */
    strcat(keyp,(lform) ? "Function-" : "F");
    NumToString(key,keyp+strlen(keyp));
    return(keyname);
  }
 
  if (key < 040)			/* a control character? */
  {
   strcat(keyp,(lform) ? "Control-" : "^"); /* yes, indicate control */
   key += 0100;				/* normalize */
  }
 
  if (ismeta)				/* a meta character? */
   strcat(keyp,(lform) ? "Meta-" : "M-"); /* yes, indicate meta typed */
  
  keyc[0] = key;
 
  if (key == 0177)			/* delete? */
   strcat(keyp,(lform) ? "Delete" : "DEL"); /* yes, use this name */
  else strcat(keyp,keyc);		/* else put printable key in */
    
  return(keyname);			/* return the name */
}
 
/* namescode - given a scan code and modifier bits, return a string
 *    	       describing this set of depressed keys in Mac language.
 *
 */
 
char *namescode(scode,mod) 
{
 static char scodename[100];
 char *scodep;
 int k;
 
 scodep = scodename;
 scodename[0] = 0;
 
 if (mod & optionKey) strcat(scodep,"Option ");
 if (mod & cmdKey) strcat(scodep,"Command ");
 if (mod & alphaLock) strcat(scodep,"Caps Lock ");
 if (mod & shiftKey) strcat(scodep,"Shift "); 
 for (k=0; k < NKEYS; k++)
  if (keycodes[k].kcode == scode) 
  { strcat(scodep,keycodes[k].kname); break; }
 return(scodename);
}
 
setnum(hdl,val)
Handle hdl;
{
 char numbuf[20];
 
 NumToString(val,numbuf);
 SetIText((Handle) hdl,numbuf);
}
 
getnum(hdl,cell)
int *cell;
Handle hdl;
{
 char numbuf[20],c;
 int i;
 
 GetIText((Handle) hdl,numbuf);
 for (i=0; (c = numbuf[i]) != 0; i++)
 if (!isdigit(c))
 {
  printerr("Field contains a non numeric ",c);
  return(FALSE);
 }
 StringToNum(numbuf,cell);
 if (*cell > 0177 || *cell < 0)
 {
  printerr("Not in 7 bit range: ",*cell);
  return(FALSE);
 }
 return(TRUE);
}

/* drawkb - called by modal dialog to update KB.
 *
 * This is the only procedure that draws or updates the KB picture.  It
 * is called by ModalDialog for normal reasons (an overlapping window
 * has gone away) or the call can be caused by our code issuing an
 * InvalRect.  In order to do things quickly we control the amount to
 * be redrawn with 3 flags:
 *
 *    ourupdate - if FALSE then an entire redraw needs to be done.
 *    updatemods - if TRUE then characters within the keys need redrawing.
 *    updatekeys - if TRUE then selected (hi-lighted) keys have changed.
 *
 */
 
drawkb()
{
  struct {
    short item;
    WindowPtr w;
  } args;
 
  getpargs(&args,sizeof(args));
  EraseRect(&kbbox);			/* start with a clean slate */
  drawkeyboard(&kbbox);			/* draw the KB outline */
  drawkeychars(keymods);		/* do update on characters */
  hilitemods(keymods);			/* draw highlighted mod keys */  
  if (keysel != KC_NUN)			/* do the current key */
   hilitekey(keysel);			/* ... */  
}
 
int keycodemods(keyc)
{
  switch(keyc)
  {
    case KC_OPT: return(optionKey);
    case KC_CMD: return(cmdKey);
    case KC_KLK: return(alphaLock);
    case KC_SHF: return(shiftKey);
    default: return(0);
  }
}

setkeydialog()
{  
  WindowPtr w;
  BOOL ismeta,isfkey;
  int itype,itemhit,kval;
  ControlHandle setkeyhdl,setfkeyhdl;
  Handle ihdl,kvalhdl,mkeyhdl;
  char nambuf[256];
 
  w = GetNewDialog(DLOG_SETK,NILPTR,(WindowPtr) -1);
  SetPort(w);				/* set the port */
 
  GetDItem(w,SETKD_KEYB,&itype,&ihdl,&kbbox);
  SetDItem(w,SETKD_KEYB,itype,(Handle ) drawkb,&kbbox);
   
  initkeyrects();			/* now that kbbox is set */
  
  mkeyhdl = gethdl(SETKD_KEYT,w);
  kvalhdl = gethdl(SETKD_KVAL,w);
  setkeyhdl = getctlhdl(SETKD_SET,w);
  setfkeyhdl = getctlhdl(SETKD_SETFK,w);
 
  HiliteControl(setkeyhdl,dimHilite); 	/* these are not allowed */  
  HiliteControl(setfkeyhdl,dimHilite); 	/* these are not allowed */  
  SelIText(w,SETKD_ITXT,0,0); 		/* select invisible text */  
 
  keymods = 0;				/* current modifiers from keyboard  */
  butmods = 0;				/* current modifiers from button */
  keysel = KC_NUN;			/* selected key */
  kbselected = TRUE;			/* kb or text is active */  
  
  ShowWindow(w);  
 
  for (;;) {				/* begin dialog loop */
    ModalDialog(myfilter,&itemhit);	/* do modal dialog */
    
    switch (itemhit) {
      
      case SETKD_KEYB:			/* mouse down in keyboard */
	if (keysel == KC_NUN)
      	 break;				/* nothing to do */
      	kbselected = TRUE;		/* KB is selected */
	SelIText(w,SETKD_ITXT,0,0); 	/* select invisible text */
	kval = mapkey(keysel,keymods,&ismeta,&isfkey);
	setnum(kvalhdl,kval);
	strcpy(nambuf,namescode(keysel,keymods));
	strcat(nambuf," is mapped to ");
	strcat(nambuf,namekey((CHAR) kval,ismeta,isfkey,TRUE));
	strcat(nambuf,".   Enter new value: ");
	SetIText(mkeyhdl,nambuf);	
	HiliteControl(setfkeyhdl,noHilite);	/* these are now allowed */
	HiliteControl(setkeyhdl,noHilite);	/* these are now allowed */
	break;
 
      case SETKD_KVAL:
      	kbselected = FALSE;		/* deselect KB */
      	if (getnum(kvalhdl,&kval)) 	/* get the number */
	{
	  strcpy(nambuf,namescode(keysel,keymods));
	  strcat(nambuf," is mapped to ");
	  strcat(nambuf,namekey((CHAR) kval,ismeta,isfkey,TRUE));
	  strcat(nambuf,".   Enter new value: ");
	  SetIText(mkeyhdl,nambuf);	
	}
	else				/* badly formed -- so reset it */
	  setnum(kvalhdl,(int) mapkey(keysel,keymods,&ismeta,&isfkey));
	break;
	  
      case SETKD_SETFK:
      case SETKD_SET:
      	if (getnum(kvalhdl,&kval))
	{
	  modified = TRUE;		/* things have changed */
	  if (itemhit == SETKD_SETFK)
	    kval |= FKEYBIT;		/* turn on function key bit */
      	  setmapkey((CHAR) kval,keysel,keymods);
	  drawkeychars(keymods);	/* do update on characters */
	  hilitemods(keymods);		/* draw highlighted mod keys */
	  if (keysel != KC_NUN)		/* something to keep hi-lited? */
	    hilitekey(keysel);		/* yes... do it */
	  kbselected = TRUE;		/* keyboard is active */
	  SelIText(w,SETKD_ITXT,0,0); 	/* select invisible text */  	    
	}
	break;
 
      case SETKD_QUIT:
      	DisposDialog(w);
	return;
	break;
     }
  }
}
 
 
 
<<< ckmke3.c >>>
/*
 * CKMKE3.C 
 *
 * Key-Config is a keyboard configurator program for use with Columbia's
 * MacKermit.
 *
 * Bill Schilit, April 1985
 *
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#include "mac/quickdraw.h"		/* order does matter */
#include "mac/osintf.h"			/*  on these... */
#include "mac/toolintf.h"
#include "mac/packintf.h"
#include "ckmkey.h"
#include "ckmkkc.h"
#include <ctype.h>
 
WindowPtr setfw;
#define setfwd ((DialogRecord *) setfw)	/* coerced to point to dlg */
 
BOOL dirty = FALSE;			/* if display need saving */
int oldtop = -1;			/* previous topline */
 
int fdisp[] = {SETFD_ST1,SETFD_ST2,SETFD_ST3,SETFD_ST4,SETFD_ST5,0};
int fvals[] = {SETFD_ET1,SETFD_ET2,SETFD_ET3,SETFD_ET4,SETFD_ET5,0};
 
#define NFDISPS 5			/* number of functions displayed */
 
char *fkeys[NFKEYS];			/* unparsed function defs */
 
char TEXT[] = {"TEXT"};			/* long aligned "text" */
char APPL[] = {"APPL"};			/* long aligned "appl" */
 

/* octout - translate number to backslash followed by 3 octal digits */
 
char *octout(s,n)
char *s;
{
 *s++ = '\\';				/* do backslash */
 *s++ = ((n >> 6) & 07) + '0';		/* first digit */
 *s++ = ((n >> 3) & 07) + '0';		/* second digit */
 *s++ = (n & 07) + '0';			/* yes, you guessed it, third digit */
 return(s);
 SYM(OCTOUT);
}
 
#define isnoctal(c) (c < '0' || c > '7')
 
char *octin(s,val)
int *val;
char *s;
{
  *val = ((s[0] - '0') << 6 | (s[1] - '0') << 3 | (s[2] - '0'));
  if (isnoctal(s[0]) || isnoctal(s[1]) || isnoctal(s[2]))
   *val = 0xff+1;			/* indicate error */
  return(&s[3]);			/* return updated ptr */
}       

/* updatefkey - given item number and function key index, update fkey
 *    	        array from edit text item.
 *
 */
 
updatefkey(rid,fkn)
{
  char etbuf[256];
 
  GetIText(gethdl(rid,setfw),etbuf);	/* get the text */
  DisposPtr(fkeys[fkn]);		/* dispose old ptr */
  fkeys[fkn] = NewPtr(strlen(etbuf)+1); /* assign storage */
  strcpy(fkeys[fkn],etbuf);		/* copy it in */
  return;
  SYM(GETFKEYS);
}

/* updatefdisp - Update the function key strings on the screen and in the
 *    	        fkeys array.
 *
 */
 
int oldself,oldsels,oldsele;
 
updatefdisp(newtop)
{
  char nambuf[10];
  int i,t;
  
/* check for the selection range... is it in our window? If so then */
/* update the values we remember - the function number, and the range. */
 
  if ((t = setfwd->editField+1) != SETFD_ETI) {
    for (i=0; fvals[i] != 0; i++)	/* locate by ID */
      if (fvals[i] == t)		/* found it? */
      	oldself = oldtop+i;		/* yes, set selected fcn number */
    oldsels = (*setfwd->textH)->selStart; /* set selection start */
    oldsele = (*setfwd->textH)->selEnd;	/* and selection end */
  }
 
  SelIText(setfw,SETFD_ETI,0,0);	/* make selection be invisible, */
					/*  prevents odd looking updates */
					/*  during scrolling */
 
/* if "dirty" is set then update fkeys array from edit text items */
 
  if (dirty)				/* if something may have changed */
    for (i=0; fvals[i] != 0; i++)	/* then loop saving edit text items */
     updatefkey(fvals[i],oldtop+i);	/*  into fkey array */
 
  dirty = FALSE;			/* nothing dirty any longer */
      
  if (oldtop != newtop)			/* if some work needs to be done */
    for (i=0, t = newtop; fdisp[i] != 0; i++)
    {
      nambuf[0] = 'F';
      NumToString(t,&nambuf[1]);
      SetIText(gethdl(fdisp[i],setfw),nambuf);
      SetIText(gethdl(fvals[i],setfw),fkeys[t++]);
    }    
 
/*
 * Manage the selection range: let the edit text selection range move
 * around, sticking with the function definition it was being used with.
 * If the function is not visible, then use already selected invisible item.
 */
 
  if (oldself >= newtop && oldself < newtop+NFDISPS)
    SelIText(setfw,fvals[oldself-newtop],oldsels,oldsele);
    
  oldtop = newtop;			/* remember for next time */
  return;
  SYM(UPDATENAMES)
}

pagescroll(part,ctl)
ControlHandle ctl;
{
  Point p;
  int amount = (part == inPageUp) ? -NFDISPS : NFDISPS;
  
  do {
    GetMouse(&p);
    if (TestControl(ctl,&p) != part)
      continue;
    SetCtlValue(ctl,GetCtlValue(ctl)+amount);
    updatefdisp(GetCtlValue(ctl));
  } while (StillDown());
  return;
  SYM(PAGESCROLL);
}
    
scrollbtn()
{
  struct {				/* args passed from Pascal */
    short part;				/*  TrackControl in stack order */
    ControlHandle ctlh;
  } args;
  int delta;
 
  getpargs(&args,sizeof args);
  
  switch (args.part) {
    case inUpButton: 
      delta = -1;
      break;
    case inDownButton:
      delta = 1;
      break;
    default: 
      return;
   }
   SetCtlValue(args.ctlh,GetCtlValue(args.ctlh)+delta);
   updatefdisp(GetCtlValue(args.ctlh));
   return;
   SYM(SCROLLBTN);
}
 

setfkfilter()
{
  struct {				/* pascal args for filter procedure */
    short *item;			/* (in stack order) */
    EventRecord *evt;    
    DialogPtr dlg;
  } args;
  BOOL *fcnret;
  Point lpt;
  ControlHandle ctlhdl;
  int part;
 
  fcnret = (BOOL *) getpargs(&args,sizeof args);
  *fcnret = FALSE;			/* assume we don't want to handle */
 
  if (args.evt->what == keyDown)	/* key down? */
  {
    if (((DialogRecord *) args.dlg)->editField == SETFD_ETI-1)
    {					/* typing to invisible selection? */
      SysBeep(1);			/* yes... beep them */
      *fcnret = TRUE;			/* do not let modal do anything */
      *args.item = SETFD_ETI;		/* a no-op */
      return;				/* and return now */
    }
    dirty = TRUE;			/* else things may change */
  }
 
  if (args.evt->what != mouseDown)	/* is this mouse down? */
    return;				/* no, we don't do anything */
  
  lpt = args.evt->where;		/* copy the point */
  GlobalToLocal(&lpt);			/* convert to local coords */
 
  part = FindControl(&lpt,args.dlg,&ctlhdl); /* find a control if any */
  
  switch (part) {
    case inUpButton:
    case inDownButton:
      TrackControl(ctlhdl,&lpt,scrollbtn);
      break;
    case inPageUp:
    case inPageDown:
      pagescroll(part,ctlhdl);
      break;
    case inThumb:
      TrackControl(ctlhdl,&lpt,NILPROC);
      updatefdisp(GetCtlValue(ctlhdl));
      break;
    default:
      return;
  }
  *fcnret = TRUE;			/* we handled it */
  return;
  SYM(SETFKFILTER)
}
 

/* getindstr - given an indirect (or is it indexed) string and integer
 *    	       n, return the pointer to the Nth substring.
 *
 * Indirect strings have the count of substrings in the first byte and
 * each string follows with a length byte and a body.
 *
 * Substrings are referenced by 1..N
 *
 */
 
char *getindstr(indstr,n)
char *indstr;
{
  register char *ip = indstr;
  int i;
 
  if (n > *ip++)			/* too large? */
   return(NILPTR);			/* yes, nothing there */
 
  for (i=1; i < n; i++)			/* scan until we hit the Nth */
   ip += (*ip)+1;			/* move to next substring */
 
  return(ip);				/* return ptr to it */
  SYM(GETINDSTR);
}

/* chkcodestr - checks a backslash coded string for correctness. */
 
chkcodestr(s,ber,eer)
char *s;
int *ber,*eer;				/* start and end of error */
{
  char *pi,*pix;
  int val;
 
  for (pi = s; *pi != NULL; ) 		/* check the string */
    if (*pi++ == '\\') {		/* found something? */
      pix = octin(pi,&val);		/* yes, fetch number */
      if (val > 0xff) {			/* error? */
	*ber = pi-s-1;			/* start of error */
	*eer = pi-s+3;			/* end of error */
	return(FALSE);			/* failed */
      }
      pi = pix;				/* update ptr */
    }					/* and loop */
  return(TRUE);
}
 
/* encodestr - encode backslash string, return NewPtr string. */
 
char *encodestr(s) 
char *s;				/* actually pascal string */
{
  char buf[256],			/* big buf */
       *dp = buf,			/* destination ptr */
       *sp = s,				/* source ptr */
       *newp;
  int len,olen;
 
  len = (sp != NILPTR) ? *sp++ : 0;	/* decide on length */
  for (dp = buf, olen = 0;		/* deposit into our buffer */
       len > 0 && olen < 64; len--) {	/* for each byte in string */ 
    olen++;				/* one more in destination */
    if (isprint(*sp) || *sp == ' ')	/* is it printable or space? */
      *dp++ = *sp++;			/* yes, just copy it */
    else {
      dp = octout(dp,*sp++);		/* else use backslash and digits */
      olen += 3;			/* account */
    }
  }
  *dp++ = 0;				/* tie off */
  newp = (char *) NewPtr(olen+2);	/* allocate storage */
  strcpy(newp,buf);			/* copy definition */
  return(newp);				/* return it */
}
 
 
/* decodestr - decode backslash string in place, make a pascal string
 *    	       returns size.
 */
 
decodestr(s) 
char *s;
{
  char *pi,*po;
  int li,lo,val;
 
  c2pstr(pi = s);			/* convert to pascal string */
 
  for (li = *pi++, lo=0, po=pi; 	/* init lengths, output ptr */
       li > 0; li--) {			/* do the entire string */
    if (*pi == '\\') {			/* special character? */
      pi = octin(++pi,&val);		/* yes fetch value (checked already) */
      *po++ = val;			/* store it */
      li -= 3;				/* account for digit bytes */
    } else *po++ = *pi++;		/* else just copy */
    lo++;				/* count up output chars */
  }    
  s[0] = lo;				/* set size */
  return(lo);				/* return size */
}
 

/* bldindstr - build an indexed string from fkeys array and return
 *    	       a relocatable handle to the new indexed string.
 *
 * An indexed string is contains the count of substrings in the first
 * byte and each string in pascal form (length byte then body) follows.
 *
 * This routine takes the contents of fkeys and translate the backslash
 * numbers to single bytes.  This conversion is done in place, as we
 * know the result will always be leq in size.  Since the final form
 * requires pascal form strings, and since the backslash might result 
 * in imbedded nulls, we first convert fkeys to pascal strings.
 *
 * The count of substrings in the indexed string will probably be less 
 * than NFKEYS (the number of definable function keys) since the last
 * batch of empty definitions need not be included.
 *
 * The resulting indexed string is allocated from the heap, it is
 * set non-purgeable, but it is relocatable.  A handle to this 
 * uber-string is returned.
 *
 * N.B. Don't try using fkeys after this routine has been called
 * since it now contains decoded strings, not backslash strings.
 *
 */
 
Handle bldindstr()
{
  int i,l,
      hifk = 0,				/* number of idx strings */
      tsize = 0;			/* total size of these */
  char *fki,*fko;
  Handle rp;
 
  for (i=0; i < NFKEYS; i++) {		/* modify strings in place */
    tsize += (l = decodestr(fkeys[i]));	/* decode the string in place */
					/*  accumulate size */
    if (l > 0) hifk = i;		/* remember highest with body */
  }
    
  tsize += hifk+1;			/* hifk is how many, add size bytes */
 
  rp = NewHandle(tsize+1);		/* get stg + count byte */
  HNoPurge(rp);				/* don't remove us */
  fko = *rp;				/* de-reference handle */
  *fko++ = hifk+1;			/* store count of substrings */
  
  for (i=0; i <= hifk; i++)		/* now store them */
  {
    fki = fkeys[i];			/* handle on input string */
    BlockMove(fki,fko,fki[0]+1);	/* move it to output */
    fko += fki[0]+1;			/* increment output ptr  */
  }
  
  return(rp);				/* return ptr */
  SYM(BLDINDSTR);			/* for debugging */
}
 

/* savefkeys - Check & save the fkeys array.
 *
 * The fkeys array is checked for correctnes (backslash badness).  If
 * something is wrong we will put the bad definition in a visible edit
 * text item in the display (if already visible no movement occurs)
 * select the bogus region, beep and return FALSE.
 *
 * If no badness is detected we release the current kset function def
 * handle, call buildidx to create a new one, store it, and return TRUE.
 *
 */
 
BOOL savefkeys(sctl)
ControlHandle sctl;
{
  int n,ctlv,sbeg,send;
 
  updatefdisp(GetCtlValue(sctl));	/* make sure fkeys updated */
 
  for (n=0; n < NFKEYS; n++) {		/* for all keys, check correctness */
    if (!chkcodestr(fkeys[n],&sbeg,&send)) {  /* check out? */
      ctlv = GetCtlValue(sctl);		/* no, get control setting */
      if (n > ctlv+NFDISPS || n < ctlv)	/* if N is not in our window */	
      	ctlv = n;			/*  need to reposition */
      SetCtlValue(sctl,ctlv);		/* set it */
      updatefdisp(ctlv);		/* update the function display */
      SelIText(setfw,			/* selects zeroth or 1st, 2nd */
      	       fvals[(n - ctlv)],	/*  edit item according to top */
	       sbeg,send);		/* region of badness */
      SysBeep(2);			/* beep them */
      return(FALSE);			/* and indicate error */
    }
  }    
  DisposHandle((*kshdl)->fcnshdl);	/* return old handle */
  (*kshdl)->fcnshdl = bldindstr();	/* build new one */
  return(TRUE);
  SYM(SAVEFKEYS);
}

/* initfkeys - given a ptr to the indexed string for function keys
 *    	       decode this string into the fkeys array.  
 *
 * Decoding is simply converting non-printable characters to backslash
 * followed by 3 octal digits.  Storage for encoded fkeys is allocated
 * in this routine, no modification is made to the indexed string.
 *
 */
 
initfkeys(indstr)
char *indstr;
{
  char *sp;
  int n;
  
  for (n=0; n < NFKEYS; n++) {		/* do all of functions */
    sp = getindstr(indstr,n+1);		/* get ptr to indexed string */
    fkeys[n] = encodestr(sp);		/* encode it */
  }
  return;
  SYM(INITFKEYS);
}
 

/* disposfkeys() - return storage used by fkeys array.
 *
 */
 
disposfkeys()
{
  int i;
 
  for (i=0; i < NFKEYS; i++)
    if (fkeys[i] != NILPTR)
    {
      DisposPtr((Ptr) fkeys[i]);	/* a comment: return it */
      fkeys[i] = NILPTR;
    }
}

setfkeydialog()
{
  int itemhit;
  ControlHandle scrollctl;
  Handle fkhdl;
  
  setfw = GetNewDialog(DLOG_SETF,NILPTR,(WindowPtr) -1);
  scrollctl = getctlhdl(SETFD_SCR,setfw);
  SetCtlMax(scrollctl,NFKEYS-NFDISPS);	/* make value */
 
  SetPort(setfw);			/* make globaltolocal work right */
  dirty = FALSE;			/* nothing is dirty */
  oldtop = -1;				/* previous topline */
  
  fkhdl = (*kshdl)->fcnshdl;		/* handle to function defs */
  HLock(fkhdl);				/* lock default key defs */
  initfkeys(*fkhdl);			/* de-ref and init fkeys array */
  HUnlock(fkhdl);			/* unlock the handle */
 
  updatefdisp(0);
  ShowWindow(setfw);
  for (;;) {
    ModalDialog(setfkfilter,&itemhit);
    switch (itemhit) {
      case SETFD_SCR:
      	break;
      case SETFD_SET:
      	if (!savefkeys(scrollctl))	/* try to save it... */
      	 break;				/* if fail, continue dialog */
	modified = TRUE;		/* things have changed */
      case SETFD_QUIT:			/* else fall into quit case */
      	DisposDialog(setfw);
	disposfkeys();			/* dispose fkeys array */
	return;
    }
  }
  SYM(SETFKDIALOG)
}

/* hexout - translate the byte to two octal digits. */
 
char hdigits[] = "0123456789abcdef";
 
hexout(dp,hc)
char hc,*dp;
{
  *dp++ = hdigits[(hc >> 4) & 0x0f];  
  *dp++ = hdigits[hc & 0x0f];
}
 
/* writehexhdl - given a file number, a handle, output the handle
 *    	      	 in hex to the file.
 *
 */
 
writehexhdl(okflg,f,hdl)
int *okflg;
Handle hdl;
{
  char *s,lb[100];			/* line buffer */
  PLONG oc,l;
 
  if (!*okflg)				/* error occured */
   return;				/*  just return */
 
  if ((l = GetHandleSize(hdl)) == 0)	/* find size, anything to do? */
   return;				/* nope... */
 
  HLock(hdl);				/* lock the handle */
  s = *hdl;				/* de-reference */
 
  oc = 0;				/* output count */
  
  for (; l > 0; l--) {			/* for each character */
    hexout(&lb[oc],*s++);		/* put in digits */
    oc += 2;				/* account */
    if (oc > 75 || l == 1) {		/* new line needed? */
      lb[oc++] = '\n';			/* yes, add nl character */
      if (!(*okflg = syserr(FSWrite(f,&oc,lb))))	/* output it */
      	return;				/* couldn't */
      oc = 0;				/* init count */
    } 
    else lb[oc++] = ' ';		/* else format */
  }
  HUnlock(hdl);				/* unlock... */
  return(TRUE);				/* done ok */
  SYM(WRITEHEXH);			/* for debugger */
}
 
writestr(okflg,f,s)
int *okflg;
char *s;
{
  PLONG l;
  int err;
 
  if (!*okflg)				/* error occured, so nop */
   return;
   
  l = strlen(s);
  *okflg = syserr(FSWrite(f,&l,s)); 	/* set to FALSE if error */
}
  
writetype(okflg,f,type)
int *okflg;
char *type;
{
  char numbuf[10];
 
  writestr(okflg,f,"\nType ");
  writestr(okflg,f,type);
  writestr(okflg,f," = HEXA\n ,");
  NumToString(KSVER,numbuf);
  writestr(okflg,f,numbuf);
  writestr(okflg,f,"\n");
}
 

/* Decompile the current file */
 
decomdialog(name)
char *name;
{
  SFReply sfr;
  char defnam[256];
  Point where;
  int fnum,err,okflg;
 
  strcpy(defnam,name);			/* copy name */
  strcat(defnam,"R");			/* here is new form... */
 
  SetPt(&where,75,100);			/* some place */
  SFPutFile(&where,"Save decompiled information in:",
      	    defnam,NILPROC,&sfr);
 
  if (!sfr.good)			/* really want to? */
   return;				/* nope... */
 
  err = FSDelete(isapstr(sfr.fName),sfr.vRefNum); /* delete old file */
  if (err != noErr && err != fnfErr)  {
    syserr(err);			/* do message */
    return;				/* and return */
  }
 
  if (syserr(Create(isapstr(sfr.fName),sfr.vRefNum,APPL,TEXT)))
    return;				/* forget it */
  
  if (syserr(FSOpen(isapstr(sfr.fName),sfr.vRefNum,&fnum)))
    return;				/* forget it */
  
  okflg = TRUE;				/* everything is ok... */
  writestr(&okflg,fnum,"* Decompiled information from ");
  writestr(&okflg,fnum,name);
  writestr(&okflg,fnum,"\n\n");
 
  writetype(&okflg,fnum,"FSET");
  writehexhdl(&okflg,fnum,(*kshdl)->fcnshdl);	/* write out functions */
  writestr(&okflg,fnum,"\n");
  
  writetype(&okflg,fnum,"MSET");
  writehexhdl(&okflg,fnum,(*kshdl)->metahdl);	/* write out meta string */
  writestr(&okflg,fnum,"\n");
 
  writetype(&okflg,fnum,"KSET");
  writehexhdl(&okflg,fnum,(Handle) kshdl);	/* write out key set */
  writestr(&okflg,fnum,"\n");
 
  if (syserr(FSClose(fnum)))		/* close it */
    return;				/* failed */
  return;
  SYM(DECOMDIALOG);
}
<<< ckmkey.c >>>
/*
 * CKMKEY.C 
 *
 * Key-Config is a keyboard configurator program for use with Columbia's
 * MacKermit.
 *
 * Bill Schilit, April 1985
 *
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#include "mac/quickdraw.h"		/* order does matter */
#include "mac/osintf.h"			/*  on these... */
#include "mac/toolintf.h"
#include "mac/packintf.h"
#include "ckmkey.h"
#include "ckmkkc.h"
 
KSHDL kshdl;
SFReply sfr;				/* global... */
 
OsType kermtype = {"KERM"};
OsType texttype = {"TEXT"};
char ttype[] = "TEXT";			/* want's to be long aligned */
int quit;
 
MenuHandle menus[MAX_MENU+1];
 
char MSET_TYPE[] = {"MSET"},
     FSET_TYPE[] = {"FSET"},
     KSET_TYPE[] = {"KSET"},
     *FSET_NAME = {"Kermit function keys"},
     *MSET_NAME = {"Kermit meta key prefix"},
     *KSET_NAME = {"Kermit Keys"};
 
BOOL modified;				/* if changes have been made */
 

/* gethdl - return a control handle given a resource ID */
 
Handle gethdl(item,dp)
DialogPtr dp;
{
 int itype;
 Rect ibox;
 Handle ihdl;
 
 GetDItem(dp,item,&itype,&ihdl,&ibox);
 return(ihdl);
}
 
 

/* mapkey - accepts a scan code plus modifier bits and translate this
 *    	    into an 8 bit ascii character using the KSET in ourkey.
 */
 
#define LC_IDX 0			/* use lower case map */
#define UC_IDX 1			/* use upper case map */
 
CHAR mapkey(scode,mods,ismeta,isfkey)
BOOL *ismeta,*isfkey;
{
 CHAR c;				/* returned char (unsigned) */
 int casidx = LC_IDX;			/* assume lower case */
 
 if (scode < 0 || scode > MAX_SCODE)
  printerr("Scan code not in range: ",scode);
 
 if (mods & shiftKey)			/* shift depressed? */
  casidx = UC_IDX;			/* yes, select an upper case map */
 
 if (mods & (*kshdl)->ctrlmods)		/* control? */
   c = (*kshdl)->ctrlmap[casidx][scode];	/* yes, use control table */
 else 
   if (mods & (*kshdl)->caplmods)		/* else is it caps lock? */
     c = (*kshdl)->caplmap[casidx][scode]; /*  yes, use caps lock table */
   else
     c = (*kshdl)->normmap[casidx][scode]; /*  else it is a normal character */
 
 *ismeta = (mods & (*kshdl)->metamods) ? 	/* tell about meta */
      	    TRUE : FALSE;		
 *isfkey = (c & FKEYBIT) ? 		/* tell about function keys */
      	    TRUE : FALSE;		
 return(c & ~FKEYBIT);			/* and return the character */
}
 

/* setmapkey - given a scan code, modifiers, and an 8 bit value, store
 *    	       the value in the appropriate cell of our KSET (ourkset).
 */
 
setmapkey(val,scode,mods)
CHAR val;				/* 8-bit unsigned char */
{
 int casidx = LC_IDX;
 
 if (scode < 0 || scode > MAX_SCODE)
  printerr("Scan code not in range: ",scode);
 
 if (mods & shiftKey)			/* shift depressed? */
  casidx = UC_IDX;			/* yes, select an upper case map */
 
 if (mods & (*kshdl)->ctrlmods)		/* control? */
   (*kshdl)->ctrlmap[casidx][scode] = val; /* yes, use control table */
 else 
   if (mods & (*kshdl)->caplmods)		/* else is it caps lock? */
     (*kshdl)->caplmap[casidx][scode] = val; /*  yes, use caps lock table */
   else
     (*kshdl)->normmap[casidx][scode] = val; /*  else it is a normal character */
}

printerr(s,n)
char *s;
{
 char num[10];
 
 if (n != 0)
 {
  NumToString(n,num);
  ParamText(s,num,"","");
 }
 else
  ParamText(s,"","","");
 CautionAlert(OUR_ALRT,NILPROC);
}
     
fatal(s,n)
char *s;
{
  printerr(s,n);
  ExitToShell();
}
 

/* support routines for modifier key dialog */
 
#define NILCLS 0			/* classes...  */
#define OPTCLS 1			/*  optionKey */
#define CMDCLS 2			/*  cmdKey */
#define KLKCLS 3			/*  alphaLock */
 
int normjunk,
    caplbits,
    ctrlbits,
    metabits;
 
/* restb - table for table driven dialog */
 
struct restb {
  int rid,
      rclass,				/* class */
      *rcell,				/* location of "home" */
      rbitv;				/* bit value (alphaKey, etc.) */
  ControlHandle rhdl;			/* handle to this control */
} rsmktb[] = {
  {RSMK_OPTNORM,OPTCLS,&normjunk,0,NILCTRL},
  {RSMK_OPTCTRL,OPTCLS,&ctrlbits,optionKey,NILCTRL},
  {RSMK_OPTCAPS,OPTCLS,&caplbits,optionKey,NILCTRL},
  {RSMK_OPTMETA,NILCLS,&metabits,optionKey,NILCTRL},
  {RSMK_CMDNORM,CMDCLS,&normjunk,0,NILCTRL},
  {RSMK_CMDCTRL,CMDCLS,&ctrlbits,cmdKey,NILCTRL},
  {RSMK_CMDCAPS,CMDCLS,&caplbits,cmdKey,NILCTRL},
  {RSMK_CMDMETA,NILCLS,&metabits,cmdKey,NILCTRL},
  {RSMK_KLKNORM,KLKCLS,&normjunk,0,NILCTRL},
  {RSMK_KLKCTRL,KLKCLS,&ctrlbits,alphaLock,NILCTRL},
  {RSMK_KLKCAPS,KLKCLS,&caplbits,alphaLock,NILCTRL},
  {RSMK_KLKMETA,NILCLS,&metabits,alphaLock,NILCTRL}
};
 
#define RSMKZ (sizeof (rsmktb)/sizeof(struct restb))
 
Handle getdlghdl(dp,rid)
DialogPtr dp;
{
 int itemtype;
 Rect itembox;
 Handle itemhdl;  
 
 GetDItem(dp,rid,&itemtype,&itemhdl,&itembox);
 return(itemhdl);
}
 

/* rmskinit - initialize "set modifier key" dialog, find control
 *    	      handles for each item, hilite "normal" for each
 *    	      class and then re-hilite any actual settings.
 */
 
rsmkinit(dp)
DialogPtr dp;
{
 int r;
  
 caplbits = (*kshdl)->caplmods;
 metabits = (*kshdl)->metamods;
 ctrlbits = (*kshdl)->ctrlmods;
 
 for (r=0; r < RSMKZ; r++)
  rsmktb[r].rhdl = (ControlHandle) getdlghdl(dp,rsmktb[r].rid);
 
 rsmksetcls(RSMK_OPTNORM);
 rsmksetcls(RSMK_KLKNORM);
 rsmksetcls(RSMK_CMDNORM);
 
 for (r=0; r < RSMKZ; r++)
  if (rsmktb[r].rbitv & *rsmktb[r].rcell)
   rsmksetcls(rsmktb[r].rid);
}
 
/* rsmkfinish - finish up "set modifier key" dialog.  Store results
 *    	      	into cells
 */
 
rsmkfinish()
{
 int r;
 
 metabits = caplbits = ctrlbits = 0;
 
 for (r=0; r < RSMKZ; r++)
  if (GetCtlValue(rsmktb[r].rhdl))
   *rsmktb[r].rcell |= rsmktb[r].rbitv;	/* turn on the bit */
 
 (*kshdl)->metamods = metabits;
 (*kshdl)->caplmods = caplbits;
 (*kshdl)->ctrlmods = ctrlbits;
}
  
rsmksetcls(item)
{
 int r,cls;
 
 for (r=0; r < RSMKZ; r++)		/* find the class */
  if (rsmktb[r].rid == item)
  {
   cls = rsmktb[r].rclass;    
   if (cls == NILCLS)			/* toggle? */
    SetCtlValue(rsmktb[r].rhdl,!GetCtlValue(rsmktb[r].rhdl));
   else
    SetCtlValue(rsmktb[r].rhdl,btnOn);
   break;
  }   
 
 if (cls != NILCLS)			/* if there is a class (skip meta) */
  for (r=0; r < RSMKZ; r++)
   if (rsmktb[r].rid != item && rsmktb[r].rclass == cls)
    SetCtlValue(rsmktb[r].rhdl,btnOff);
}
 
metaradios(use8,dlg)
DialogPtr dlg;
{
  SetCtlValue(getctlhdl(RSMK_M8BIT,dlg),(use8) ? btnOn : btnOff);
  SetCtlValue(getctlhdl(RSMK_MPREF,dlg),(use8) ? btnOff : btnOn);
}
 
BOOL metafinish(use8,dlg)
DialogPtr dlg;
{
  char mtxt[256];
  Handle mhdl;
  int l,sb,se;
 
  GetIText(gethdl(RSMK_METXT,dlg),mtxt); /* get meta text itself */
  
  if (use8)				/* want to use 8 bit? */
    mtxt[0] = l = 0;			/* yes, use zero length string */
  else {				/* else check out meta text */
    if (!chkcodestr(mtxt,&sb,&se)) {  	/* error in backslash? */
      SelIText(dlg,RSMK_METXT,sb,se); 	/* yes, set selection range */
      SysBeep(2);			/* tell them */
      return(FALSE);			/* and indicate failure */
    }
    l = decodestr(mtxt);		/* decode in place, get length */
  }
  
  (*kshdl)->meta8bit = use8;		/* update boolean */        
  mhdl = (*kshdl)->metahdl;		/* get old meta text handle */
  DisposHandle(mhdl);			/* rid old handle */      
  mhdl = NewHandle(l+1);		/* string size plus size byte */
  BlockMove(mtxt,*mhdl,l+1);		/* copy the string */
  return(TRUE);				/* and return ok */
}
  
dosetmkdialog()
{
 int itemhit,m8bit;
 DialogPtr dlg;
 Handle mhdl;
 char *mstr,*encodestr();
 
 dlg = GetNewDialog(DLOG_RSMK,NILPTR,(WindowPtr) -1);
 
 mhdl = (*kshdl)->metahdl;		/* get meta string */
 HLock(mhdl);				/* prevent movement */
 mstr = encodestr(*mhdl);		/* encode it */
 HUnlock(mhdl);				/* unlock */ 
 SetIText(gethdl(RSMK_METXT,dlg),mstr); /* set it */
 DisposPtr(mstr);			/* no longer needed */ 
 
 rsmkinit(dlg);				/* init settings */
 
 m8bit = (*kshdl)->meta8bit;		/* get 8 bit quote value */
 metaradios(m8bit,dlg);			/* init radio items */
 
 ShowWindow(dlg);
  for (;;) {
    ModalDialog(NILPROC,&itemhit);
    switch (itemhit) {
     case RSMK_OK:
       if (!metafinish(m8bit,dlg))	/* do meta stuff */
         break;				/* format error... */
       modified = TRUE;			/* things have changed */
       rsmkfinish();			/* store values */
 
     case RSMK_CANCEL:
       DisposDialog(dlg);
       return;
       
     case RSMK_M8BIT:
     case RSMK_MPREF:
      m8bit = (itemhit == RSMK_M8BIT);
      metaradios(m8bit,dlg);
      break;
 
     default:
       rsmksetcls(itemhit);		/* set buttons */
       break;
    }
  }
}
 

/* privrsrc - return a private copy of a resource.  The handle
 *    	      returned is relocatable but non purgeable.
 *
 */
 
Handle privrsrc(type,id,name)
char *type,*name;
{
  Handle rhdl,phdl;
  char errbuf[256];
  int l;
 
  rhdl = GetResource(type,id);		/* load the resource */
  if (rhdl == (Handle) NIL)		/* nothing? */
  {
    strcpy(errbuf,"There are no ");
    strcat(errbuf,name);
    strcat(errbuf," of the known version in this file.");
    printerr(errbuf,0);
    return((Handle) NIL);		/* then return now with NIL */
  }
 
  HLock(rhdl);				/* make sure rsrc stays around */
  phdl = NewHandle(l = SizeResource(rhdl)); /* get new relocatable block */
  HLock(phdl);				/* lock new block also */
  BlockMove(*rhdl,*phdl,l);		/* copy from resource to new block */
  HUnlock(rhdl);			/* rsrc lock no longer needed */
  ReleaseResource(rhdl);		/* rsrc completely gone now */
  HNoPurge(phdl);			/* keep new block in memory */
  HUnlock(phdl);			/* but can move around */
  return(phdl);				/* all done */
  SYM(PRIVRESOURCE);
}
 
KSHDL loadkset()
{
 Handle fhdl,mhdl;
 KSHDL khdl;
 
 khdl = (KSHDL) privrsrc(KSET_TYPE,KSVER,KSET_NAME);
 if (khdl == (KSHDL) NIL)
  return((KSHDL) NIL);
 
 fhdl = privrsrc(FSET_TYPE,KSVER,FSET_NAME);
 if (fhdl == (Handle) NIL)
  return((KSHDL) NIL);
 
 (*khdl)->fcnshdl = fhdl;		/* save handle to relocatable block */
 
 mhdl = privrsrc(MSET_TYPE,KSVER,MSET_NAME);
 if (mhdl == (Handle) NIL)
  return((KSHDL) NIL);
  
 (*khdl)->metahdl = mhdl;		/* save handle */
 
 return(khdl);				/* return the KSET handle */
 SYM(LOADKSET);
}
 
/*
 * initmenus - create the menu bar.
 * 
 */
 
initmenus()
{
  int i;
 
  for (i=MIN_MENU; i<=MAX_MENU; i++)  	/* For all menus */
  {
    menus[i] = GetMenu(i);		/* Fetch it from resource file */
    InsertMenu(menus[i],0);		/* Put it on menu line */
  }
  DrawMenuBar();			/* Finish up by displaying the bar */
  return;
  SYM(INITMENUS);
}
 

addrsrc(type,id,hdl,str)
char *type,*str;
Handle hdl;
{
  Handle rhdl;
 
  rhdl = GetResource(type,id);		/* check for old value */
  if (rhdl != NULL) {			/* something there? */
    RmveResource(rhdl);			/* yes, then delete it */
    if (ResError() != noErr)
      return(!syserr(ResError()));
  }
  
  AddResource(hdl,type,id,str);
  return(!syserr(ResError()));		/* return TRUE if ok */
}
  

/* kfilefilter - match creator "KERM" from sfgetfile call */
 
kfilefilter()
{
 FileParam *pb;				/* args from SFGetFile... */
 char *retval;
 
 retval = (char *) getpargs(&pb,sizeof(FileParam *));
 *retval = (strncmp(			/* compare creator's... and return */
      pb->ioFlFndrInfo.fdCreator.s, 	/* TRUE if not a match */
      kermtype.s,4) != 0);		/* FALSE otherwise for inclusion */
 return;
 SYM(KFILEFILTER);      
}
 
savevals(fname,fvol)
char *fname;
{
  int rfnum;
 
  SetVol(NILPTR,fvol);			/* set volume */
 
  rfnum = OpenResFile(isapstr(fname));	/* open it up */
  if (rfnum == -1)			/* could not? */
  {
    syserr(ResError());			/* handle error */
    return;				/* and return */
  }
 
  if (addrsrc(MSET_TYPE,KSVER,(*kshdl)->metahdl,MSET_NAME))
    if (addrsrc(FSET_TYPE,KSVER,(*kshdl)->fcnshdl,FSET_NAME))
      (addrsrc(KSET_TYPE,KSVER,(Handle) kshdl,KSET_NAME));
  
  CloseResFile(rfnum);
  if (syserr(ResError()))		/* error occured */
   return;
   
  FlushVol(NILPTR,fvol);		/* flush the volume */
  
  rfnum = OpenResFile(isapstr(fname)); 	/* reopen the file */
  if (rfnum == -1)			/* unable? */
  {
    syserr(ResError());
    return;
  }
  kshdl = loadkset();			/* load in files KSET */
  CloseResFile(rfnum);			/* close the file */
  if (kshdl == NIL)			/* problems */
   fatal("Unable to reload key defs!",0);
  
  modified = FALSE;			/* no longer modified */
  return;
  SYM(SAVEVALS);
}
 
 

loadvals()
{
  Point where;
  int rfnum;
 
  SetPt(&where,75,115);
  SFGetFile(&where,"Load variables from:",
      	    kfilefilter,1,ttype,NILPROC,&sfr);
  if (!sfr.good)			/* did they hit cancel? */
   return(FALSE);			/* yes, so return now */
  
  SetVol(NILPTR,sfr.vRefNum);		/* setup volume */
  rfnum = OpenResFile(isapstr(sfr.fName)); /* open up the file */
  if (rfnum == -1)			/* unable? */
    return(!syserr(ResError()));
 
  kshdl = loadkset();			/* load in files KSET */
  CloseResFile(rfnum);			/* close the file */
  if (kshdl == (KSHDL) NIL)
   return(FALSE);
  else
   return(TRUE);
  SYM(LOADVALS);
}
 

/* 
 * aboutme - Display the about KCONFIG dialog box, wait for user to
 *     	     hit the OK button (maybe this should be a mouse click).
 *
 * The KCONFIG version string is stored in the resource fork as type 
 * "KERK" ID 0 -- load this resource into memory, and lock it.  The
 * resource is locked so that we won't go off the deep end if the
 * heap gets compacted during the dialog display.  This would cause
 * problems because we are using the de-referenced handle, the actual
 * location of the string and not a pointer (handle) to it.
 *
 */
 
aboutme()
{
  Handle kversion;
  static char ktype[] = "KERK";
  DialogPtr kdialog;			/* our dialog */
 
  kversion = GetResource(ktype,0);	/* get version information */
  LoadResource(kversion);		/* make sure loaded */
  HLock(kversion);			/* prevent movement */
  ParamText(isapstr(*kversion),"","",""); /* set it up for display via ^0 */
					/*  de-reference the handle */
  kdialog = GetNewDialog(ABOUTID,NILPTR,(WindowPtr) -1);
  ShowWindow(kdialog);			/* in case hidden or something */
  DrawDialog(kdialog);			/* draw the dialog */
  while (!Button());			/* wait for button */
  DisposDialog(kdialog);		/* dispose dialog box */
  HUnlock(kversion);			/* undo previous HLock */
  ReleaseResource(kversion);		/* no longer needed */
}
 
/* maybesave - enter maybe save dialog.
 *
 * Pass the name of the operation which will zap things, for example
 * "quitting" or "opening" and we'll tell the user about the pending
 * doom of changes if they've occured.  We return TRUE if user wants
 * to proceed, FALSE otherwise.
 *
 */
 
BOOL maybesave(op)
char *op;
{
 if (!modified) 
  return;				/* no changes made */
 
  ParamText(isapstr(sfr.fName),op,"","");  /* set name, operation */
  switch (Alert(MAYBE_ALRT,NILPROC)) {
    case YES_MAYBE: 
      savevals(sfr.fName,sfr.vRefNum); /* YES: do it */
    case NO_MAYBE:
      return(TRUE);			/* NO: proceed */
  }
  return(FALSE);			/* Cancel or other... */
}
 

parser()
{
  EventRecord ev;
  WindowPtr evw;
 
  for (quit = FALSE; !quit;) {
    SystemTask();
    GetNextEvent(everyEvent,&ev);
    if (ev.what == mouseDown) {
      
      switch (FindWindow(&ev.where,&evw)) {
	
	case inMenuBar:
	  menuparser(MenuSelect(&ev.where));
	  HiliteMenu(0);		/* done so un-hilite */
	  break;
	  
	case inSysWindow:
	  SystemClick(&ev,evw);
	  break;
 
      }
    }
  }    
}
 
 
alterofferings(savok)
{
  int (*fcn)(),EnableItem(),DisableItem();
  char savbuf[256];
  
  fcn = (savok) ? EnableItem : DisableItem;
	    
  (*fcn)(menus[SETK_MENU],0);		/* enable/disable SET menu */
  (*fcn)(menus[FILE_MENU],SAVE_FILE);	/* enable/disable SAVE item */
  (*fcn)(menus[FILE_MENU],DECOM_FILE);	/* enable/disable DECOMPILE... */
  strcpy(savbuf,"Save ");		/* initial text of save */
  if (savok)				/* ok to save? */
    strncat(savbuf,&sfr.fName[1],sfr.fName[0]);	/* yes... put in name */
    
  SetItem(menus[FILE_MENU],SAVE_FILE,savbuf); /* set item */
  HiliteMenu(0);			/* de-hilite, prevents oddness */
  DrawMenuBar();			/* disable/enable menu bar items */
}

menuparser(mitem)
{
  int menu = HiWord(mitem),
      item = LoWord(mitem);
 
  switch (menu) {
    case APPL_MENU:
      switch (item) {
	case ABOU_APPL:
	  aboutme();
	  break;
	default:
	  break;
      }
      break;
 
    case FILE_MENU:
      switch (item) {
	case OPEN_FILE:
	  if (maybesave("opening"))	/* if they want... */
	    alterofferings(loadvals());	/* do it and alter menu items */
	  break;
 
        case DECOM_FILE:
	  p2cstr(sfr.fName);
	  decomdialog(sfr.fName);
	  c2pstr(sfr.fName);
	  break;
 
	case SAVE_FILE:	    
	  savevals(sfr.fName,sfr.vRefNum); /* do it */
	  break;
	  
	case QUIT_FILE:
	  if (maybesave("quitting"))	/* if they really want to */
	    quit = TRUE;		/* then let them */
	  break;
      }
      break;
 
    case SETK_MENU:
      switch (item) {
	case SKEY_SETK:
	  ScrDmpEnb = scrdmpdisabled;	/* disable special keys */
	  setkeydialog();
	  ScrDmpEnb = scrdmpenabled;	/* enable special keys */	  
	  break;
	case SMOD_SETK:
	  dosetmkdialog();
	  break;
	case FCNK_SETK:
	  setfkeydialog();
	  break;
      }
      break;
   }
}
 

/* checks for system error, returns FALSE if noErr, else puts up an error
 * message with an understandable text string.
 *
 */
 
struct {
  int errnum;
  char *errstr;
  } ioerrs[] = {
    {resNotFound,"Resource not found"},
    {resFNotFound,"Resource file not found"},
    {addResFailed,"AddResource failed"},
    {dirFulErr,"Directory is full"},
    {dskFulErr,"Disk is full"},
    {wPrErr,"Diskette is write protected"},
    {fLckdErr,"File is software locked"},
    {vLckdErr,"Volume is software locked"},
    {fBsyErr,"File is busy"},
    {opWrErr,"File is already open with write permission"},
    {0,NILPTR}
    };
 
syserr(err)
{
  int e;
 
  if (err == noErr)
   return(FALSE);
 
  for (e = 0; ioerrs[e].errnum != 0 && 
      	      ioerrs[e].errnum != err; e++);
 
  if (ioerrs[e].errstr == NILPTR)	/* anything there? */
   printerr("Unknown IO error: ",err);
  else
   printerr(ioerrs[e].errstr,0);
   
  return(TRUE);   
  SYM(SYSERR);
}
 

main() 
{
  QD = &QDVar;
 
  InitGraf(&thePort);
  InitWindows();
  InitFonts();
  InitDialogs(NILPROC);
  InitMenus();
  TEInit();
  InitCursor();
 
  initmenus();
  alterofferings(FALSE);		/* disable menu items */
  modified = FALSE;			/* not modified */
  parser();
  ExitToShell();
  SYM(MAIN);
}
 
<<< ckmkey.h >>>
/*
 * CKMKEY.H 
 *
 * Key-Config is a keyboard configurator program for use with Columbia's
 * MacKermit.
 *
 * Bill Schilit, April 1985
 *
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#define ABOUTID 257
 
typedef int PLONG;			/* pascal long in sumex */
typedef unsigned char BOOL;
typedef unsigned char CHAR;
#define NIL 0
#define NULL 0
#define NILPTR (Ptr) NIL
#define NILPROC (ProcPtr) NIL
#define NILCTRL (ControlHandle) NIL
#define TRUE 1
#define FALSE 0
 
#define btnOff	0
#define btnOn	1
 
/* Resource IDS for "Maybe Save" alert */
 
#define MAYBE_ALRT 2			/* alert number */
#define YES_MAYBE 1			/* each button */
#define NO_MAYBE 2
#define CANCEL_MAYBE 3
 
/* Resource IDS for "Set Modifier Keys" Dialog */
 
#define RSMK_OK 1
#define RSMK_CANCEL 2
#define RSMK_OPTNORM 4
#define RSMK_OPTCTRL 5
#define RSMK_OPTCAPS 6
#define RSMK_OPTMETA 7
#define RSMK_KLKNORM 9
#define RSMK_KLKCTRL 10
#define RSMK_KLKCAPS 11
#define RSMK_KLKMETA 12
#define RSMK_CMDNORM 14
#define RSMK_CMDCTRL 15
#define RSMK_CMDCAPS 16
#define RSMK_CMDMETA 17
#define RSMK_M8BIT 18
#define RSMK_MPREF 19
#define RSMK_METXT 20
 
#define dimHilite 255
#define noHilite 0
 
#define DLOG_RSMK 1001			/* set modifier key dialog */
 
#define OUR_ALRT 1
 
struct QDVar QDVar;
 
/* getctlhdl - same as above but for controls */
 
#define getctlhdl(item,dp) (ControlHandle) gethdl(item,dp)
 

#define MIN_MENU 1
#define APPL_MENU 1
#define  ABOU_APPL 1
#define FILE_MENU 2
#define  OPEN_FILE 1
#define  SAVE_FILE 2
#define  DECOM_FILE 3
#define  QUIT_FILE 4
#define SETK_MENU 3
#define  SKEY_SETK 1
#define  SMOD_SETK 2
#define  FCNK_SETK 3
#define MAX_MENU 3
 
/* Set function definitions item ids */
 
#define DLOG_SETF 1002			/* set function DLOG ID */
 
#define SETFD_SET 1
#define SETFD_QUIT 2
#define SETFD_ST1 3
#define SETFD_ET1 4
#define SETFD_ST2 5
#define SETFD_ET2 6
#define SETFD_ST3 7
#define SETFD_ET3 8
#define SETFD_ST4 9
#define SETFD_ET4 10
#define SETFD_ST5 11
#define SETFD_ET5 12
#define SETFD_SCR 13
#define SETFD_ETI 14			/* invisible edit text */
 
/* Set Key Dialog item ids */
 
#define DLOG_SETK 1000			/* set key DLOG ID */
 
#define SETKD_SET 1			/* set key button */
#define SETKD_QUIT 2			/* quit button */
#define SETKD_SETFK 3			/* set function key */
#define SETKD_KEYB 4			/* keyboard pict, user item */
#define SETKD_KEYT 5			/* text for key name prompt */
#define SETKD_KVAL 6			/* edit text */
#define SETKD_ITXT 7			/* invisible text */
 
 
#define K_UNIT 8
#define K_HEIGHT 4*K_UNIT		/* need 6/4, 7/4, 9/4 below... */
 
#define R1 K_HEIGHT		 	/* normal key size */
#define R2 6*K_UNIT 			/* backspace, tab, enter, option */
#define R3 7*K_UNIT			/* caps lock, return size */
#define R4 9*K_UNIT	 		/* shift size */
#define R5 (7*K_HEIGHT)			/* return size */
 
#define KC_CMD 0x37			/* scan code for cmd */
#define KC_SHF 0x38			/* code for shift */
#define KC_KLK 0x39			/* code for caps lock */
#define KC_OPT 0x3A			/* code for option */
 
#define KC_OPT2 0x81			/* "special" for second option key */
#define KC_SHF2 0x82			/* "special" for second shift key */
#define KC_NUN 0x84			/* "special" for no key */
 
extern Handle gethdl();
extern BOOL modified;			/* set if things have changed */
 
#define SYM(x) { \
   asm("unlk a6"); \
   asm("rts"); \
   asm(".asciz 'x'"); \
   asm(".even"); }
 
<<< ckmkkc.h >>>
/*
 * CKMKKC.H 
 *
 * This file contains common definitions for keyboard configuration
 * used between CKMKEY and CKMKER.
 *
 * Bill Schilit, May 1985
 *
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#define KSVER 2				/* current version number */
 
/* KSET is the KSET structure present in settings files */
/* FSET is the indexed string type holding function key definitions */
/* MSET is the simple (pascal) string with the meta prefix string */
 
extern char KSET_TYPE[],FSET_TYPE[],MSET_TYPE[];
 
#define MAX_SCODE 127			/* max scan code */
 
typedef struct {
  int  ctrlmods,			/* modifiers which cause control */
       metamods,			/* modifiers which cause meta */
       caplmods;			/* modifiers which cause caps */
  char normmap[2][MAX_SCODE],		/* lower/upper normal map */
       caplmap[2][MAX_SCODE],		/* lower/upper shift lock map  */
       ctrlmap[2][MAX_SCODE];		/* lower/upper control map */
  Handle
       fcnshdl,				/* handle to functions */
       metahdl;				/* handle to meta string */
  BOOL meta8bit;			/* use 8-bit for meta */
} KSET;
 
typedef KSET **KSHDL;
 
extern KSHDL kshdl;			/* handle on key set */
 
#define FKEYBIT 0200			/* high bit means function key */
#define METABIT 0200			/* turned on for meta */
 
  					/* special functions: */
#define SPFSBRK 0176			/*  short break */
#define SPFLBRK 0177			/*  long break */
 
/* number of user programmable functions, which is 0-0175, 0-125. 
 * thats 0177 less specials defined above.
 */
 
#define NFKEYS (0177-2+1)
 
#define LC_IDX 0			/* use lower case map */
#define UC_IDX 1			/* use upper case map */
#define MOD_MASK (alphaLock | cmdKey | optionKey | shiftKey)  /* modifers */
 
/*
 * ScrDmpEnb is a flag byte used by the toolbox event manager to say
 * whether command-shift-1 through command-shift-9 do anything special
 * like dump the screen, eject the diskettes, etc.  This byte is used in
 * INIT0, the keyboard mapping routine (see IM index under scrdmpenb).
 *
 * N.B: The location of this value may change if MAC comes out with a
 * new SYSTEM.
 *
 */
 
#define ScrDmpEnb (*(unsigned char *) 0x2f8)
#define scrdmpenabled ((unsigned char) 0xff)
#define scrdmpdisabled ((unsigned char) 0x00)
 
<<< ckmpro.c >>>
 
/* WARNING -- This C source program generated by Wart preprocessor. */
/* Do not edit this file; edit the Wart-format source file instead, */
/* and then run it through Wart to produce a new C source file.     */
 
/* Wart Version Info: */
char *wartv = "Wart Version 1A(003) 27 May 85";
 
char *protv = "C-Kermit Protocol Module 4C(029), 11 Jul 85"; /* -*-C-*- */
 
/* C K C P R O  -- C-Kermit Protocol Module, in Wart preprocessor notation. */
/*
 Authors: Frank da Cruz (SY.FDC@CU20B), Bill Catchings, Jeff Damens;
 Columbia University Center for Computing Activities, January 1985.
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained. 
*/
#include "ckcdeb.h"
#include "ckcker.h"
/*
 Note -- This file may also be preprocessed by the Unix Lex program, but 
 you must indent the above #include statements before using Lex, and then
 restore them to the left margin in the resulting C program before compilation.
 Also, the invocation of the "wart()" function below must be replaced by an
 invocation  of the "yylex()" function.  It might also be necessary to remove
 comments in the %%...%% section.
*/
 
/* State definitions for Wart (or Lex) */
#define ipkt 1
#define rfile 2
#define rdata 3
#define ssinit 4
#define ssfile 5
#define ssdata 6
#define sseof 7
#define sseot 8
#define serve 9
#define generic 10
#define get 11
#define rgen 12
 
/* External C-Kermit variable declarations */
  extern char sstate, *versio, *srvtxt, *cmarg, *cmarg2;
  extern char data[], filnam[], srvcmd[], ttname[], *srvptr;
  extern int pktnum, timint, nfils, image, hcflg, xflg, speed, flow, mdmtyp;
  extern int prvpkt, cxseen, czseen, server, local, displa, bctu, bctr, quiet;
  extern int tsecs;
  extern int putsrv(), puttrm(), putfil(), errpkt();
  extern char *DIRCMD, *DELCMD, *TYPCMD, *SPACMD, *SPACM2, *WHOCMD;
 
/* Local variables */
  static char vstate = 0;  		/* Saved State   */
  static char vcmd = 0;    		/* Saved Command */
  int x;				/* General-purpose integer */
  char *s;				/* General-purpose string pointer */
 
/* Macros - Note, BEGIN is predefined by Wart (and Lex) */
#define SERVE  tinit(); BEGIN serve
#define RESUME if (server) { SERVE; } else return
 
 
#define BEGIN state =
 
int state = 0;
 
wart()
{
  int c,actno;
  extern unsigned char tbl[];
  while (1) {
	c = input();
	if ((actno = (int) tbl[c + state*128]) != -1)
	  switch(actno) {
case 1:
{ tinit();	    	    	    	/* Do Send command */
    if (sinit()) BEGIN ssinit;
       else RESUME; }
break;
case 2:
{ tinit(); sleep(1); nack(); BEGIN get; }
break;
case 3:
{ tinit(); vstate = get;  vcmd = 0;   sipkt('I'); BEGIN ipkt; }
break;
case 4:
{ tinit(); vstate = rgen; vcmd = 'C'; sipkt('I'); BEGIN ipkt; }
break;
case 5:
{ tinit(); vstate = rgen; vcmd = 'G'; sipkt('I'); BEGIN ipkt; }
break;
case 6:
{ sleep(1); SERVE; }
break;
case 7:
{ errpkt("User cancelled transaction"); /* "Abort" -- Tell other side. */
    x = quiet; quiet = 1; 		/* Close files silently. */
    clsif(); clsof(1); 
    quiet = x; return(0); }
break;
case 8:
{ rinit(data); bctu = bctr; /* Get Send-Init */
    	   rtimer(); BEGIN rfile; }
break;
case 9:
{ spar(data);			/* Get ack for I-packet */
    	   if (vcmd) { scmd(vcmd,cmarg); vcmd = 0; }
    	   if (vstate == get) srinit();
	   BEGIN vstate; }
break;
case 10:
{ if (vcmd) scmd(vcmd,cmarg);	/* Get E for I-packet (ignore) */
    	   vcmd = 0; if (vstate == get) srinit();
	   BEGIN vstate; }
break;
case 11:
{ srvptr = srvcmd; decode(data,putsrv); /* Get Receive-Init */
	   cmarg = srvcmd;  nfils = -1;
    	   if (sinit()) BEGIN ssinit; else { SERVE; } }
break;
case 12:
{ spar(data); rpar(data); ack1(data);	 /* Get Init Parameters */
	   pktnum = 0; prvpkt = -1; }
break;
case 13:
{ srvptr = srvcmd; decode(data,putsrv); /* Get & decode command. */
	   putsrv('\0'); putsrv('\0');
	   sstate = srvcmd[0]; BEGIN generic; }
break;
case 14:
{ srvptr = srvcmd;		    	 /* Get command for shell */
	   decode(data,putsrv); putsrv('\0');
	   if (syscmd(srvcmd,"")) BEGIN ssinit;
	   else { errpkt("Can't do system command"); SERVE; } }
break;
case 15:
{ errpkt("Unimplemented server function"); SERVE; }
break;
case 16:
{ if (!cwd(srvcmd+1)) errpkt("Can't change directory"); /* CWD */
    	     SERVE; }
break;
case 17:
{ if (syscmd(DIRCMD,srvcmd+2)) BEGIN ssinit;	/* Directory */
    	     else { errpkt("Can't list directory"); SERVE; } }
break;
case 18:
{ if (syscmd(DELCMD,srvcmd+2)) BEGIN ssinit;	/* Erase */
    	     else { errpkt("Can't remove file"); SERVE; } }
break;
case 19:
{ ack(); screen(SCR_TC,0,0l,""); return(0); }
break;
case 20:
{ ack(); ttres(); screen(SCR_TC,0,0l,""); return(zkself()); }
break;
case 21:
{ if (sndhlp()) BEGIN ssinit;
    	     else { errpkt("Can't send help"); SERVE; } }
break;
case 22:
{ if (syscmd(TYPCMD,srvcmd+2)) BEGIN ssinit;
    	     else { errpkt("Can't type file"); SERVE; } }
break;
case 23:
{ x = *(srvcmd+1);			/* Disk Usage query */
    	     x = ((x == '\0') || (x == unchar(0)));
	     x = (x ? syscmd(SPACMD,"") : syscmd(SPACM2,srvcmd+2));
    	     if (x) BEGIN ssinit; else { errpkt("Can't check space"); SERVE; }}
break;
case 24:
{ if (syscmd(WHOCMD,srvcmd+2)) BEGIN ssinit;
    	     else { errpkt("Can't do who command"); SERVE; } }
break;
case 25:
{ errpkt("Unimplemented generic server function"); SERVE; }
break;
case 26:
{ decode(data,puttrm); RESUME; }
break;
case 27:
{ if (rcvfil()) { ack1(filnam); BEGIN rdata; } /* File header */
		else { errpkt("Can't open file"); RESUME; } }
break;
case 28:
{ opent(); ack(); BEGIN rdata; }
break;
case 29:
{ ack(); tsecs = gtimer(); reot(); RESUME; }
break;
case 30:
{ if (cxseen) ack1("X");	/* Got data. */
    	       else if (czseen) ack1("Z");
	       else ack();
	   decode(data,putfil); }
break;
case 31:
{ if (reof() < 0) {	    	/* Got End Of File */
    	      errpkt("Can't close file"); RESUME;
    	    } else { ack(); BEGIN rfile; } }
break;
case 32:
{ spar(data); bctu = bctr;	/* Got ACK to Send-Init */
    	    x = sfile(xflg);		/* Send X or F header packet */
	    if (x) { rtimer(); BEGIN ssfile; }
	   	else { s = xflg ? "Can't execute command" : "Can't open file";
		    errpkt(s); RESUME; }
          }
break;
case 33:
{ srvptr = srvcmd;		    	 /* Got ACK to F */
	    decode(data,putsrv); putsrv('\0');
	    if (*srvcmd) tlog(F110," stored as",srvcmd,0);
	    if (sdata() < 0) { clsif(); seof(""); BEGIN sseof; }
    	    	else BEGIN ssdata; }
break;
case 34:
{ if (canned(data)) { clsif(); seof("D"); BEGIN sseof; }
	    	else if (sdata() < 0) { clsif(); seof(""); BEGIN sseof; } }
break;
case 35:
{ if (gnfile() > 0) {		/* Got ACK to EOF, get next file */
		if (sfile()) BEGIN ssdata;
		else { errpkt("Can't open file") ; RESUME; }
	    } else {			/* If no next file, EOT */
		tsecs = gtimer();
		seot();
		BEGIN sseot; }
	  }
break;
case 36:
{ RESUME; }
break;
case 37:
{ ermsg(data);			/* Error packet, issue message. */
    x = quiet; quiet = 1;		/* Close files silently, */
    clsif(); clsof(1);			/* discarding any output file. */
    tsecs = gtimer();
    quiet = x; RESUME; }
break;
case 38:
{ errpkt("Unknown packet type"); RESUME; }
break;
 
    }
  }
}
 
unsigned char tbl[] = {
-1, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 7, 38, 4, 38, 
38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 38, 2, 38, 6, 
38, 38, 38, 38, 38, 38, 38, -1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 10, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 9, 38, 38, 38, 
38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 38, 38, 38, -1, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 29, 38, 38, 37, 27, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 28, 38, 38, 38, 38, 38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 
38, 38, 38, -1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 30, 37, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 31, 38, 38, 38, 38, 38, 38, 
7, 38, 4, 38, 38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 
38, 2, 38, 6, 38, 38, 38, 38, 38, 38, 38, -1, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
32, 38, 38, 38, 38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 38, 38, 38, -1, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 33, 38, 38, 38, 38, 38, 38, 38, 7, 38, 4, 38, 
38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 38, 2, 38, 6, 
38, 38, 38, 38, 38, 38, 38, -1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 34, 38, 38, 38, 
38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 38, 38, 38, -1, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 35, 38, 38, 38, 38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 
38, 38, 38, -1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 36, 38, 38, 38, 38, 38, 38, 38, 
7, 38, 4, 38, 38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 
38, 2, 38, 6, 38, 38, 38, 38, 38, 38, 38, -1, 15, 15, 15, 15, 15, 15, 15, 15, 
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 14, 15, 
15, 15, 13, 15, 12, 15, 15, 15, 15, 15, 15, 15, 15, 11, 8, 15, 15, 15, 15, 15, 
15, 15, 15, 15, 15, 15, 15, 15, 7, 15, 4, 15, 15, 15, 5, 15, 15, 15, 15, 15, 
15, 15, 15, 15, 15, 3, 1, 15, 15, 2, 15, 6, 15, 15, 15, 15, 15, 15, 15, -1, 
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 
25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 
25, 25, 25, 25, 25, 25, 16, 17, 18, 19, 25, 21, 25, 25, 25, 20, 25, 25, 25, 25, 
25, 25, 25, 22, 23, 25, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 7, 25, 4, 25, 
25, 25, 5, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 3, 1, 25, 25, 2, 25, 6, 
25, 25, 25, 25, 25, 25, 25, -1, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 8, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 38, 38, 38, 0, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 
38, 38, 38, 38, 37, 27, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 8, 38, 
38, 38, 38, 28, 26, 38, 38, 38, 38, 38, 38, 38, 7, 38, 4, 38, 38, 38, 5, 38, 
38, 38, 38, 38, 38, 38, 38, 38, 38, 3, 1, 38, 38, 2, 38, 6, 38, 38, 38, 38, 
38, 38, 38, };
 

/*  P R O T O  --  Protocol entry function  */
 
proto() {
 
    extern int sigint();
    int x;
 
    conint(sigint);			/* Enable console interrupts */
 
/* Set up the communication line for file transfer. */
 
    if (local && (speed < 0)) {
	screen(SCR_EM,0,0l,"Sorry, you must 'set speed' first");
	return;
    }
 
    x = -1;
    if (ttopen(ttname,&x,mdmtyp) < 0) {
	debug(F111,"proto ttopen local",ttname,local);
	screen(SCR_EM,0,0l,"Can't open line");
	return;
    }
    if (x > -1) local = x;
    debug(F111,"proto ttopen local",ttname,local);
 
    x = (local) ? speed : -1;
    if (ttpkt(x,flow) < 0) {		/* Put line in packet mode, */
	screen(SCR_EM,0,0l,"Can't condition line");
	return;
    }
    if (sstate == 'x') {		/* If entering server mode, */
	server = 1;			/* set flag, */
	if (!quiet) {
	    if (!local)			/* and issue appropriate message. */
	    	conol(srvtxt);
	    else {
	    	conol("Entering server mode on ");
		conoll(ttname);
	    }
	}
    } else server = 0;
    sleep(1);
 
/*
 The 'wart()' function is generated by the wart program.  It gets a
 character from the input() routine and then based on that character and
 the current state, selects the appropriate action, according to the state
 table above, which is transformed by the wart program into a big case
 statement.  The function is active for one transaction.
*/
 
    wart();				/* Enter the state table switcher. */
    
    if (server) {			/* Back from packet protocol. */
	server = 0;
    	if (!quiet)  			/* Give appropriate message */
	    conoll("C-Kermit server done");
    }
    screen(SCR_TC,0,0l,"");		/* Transaction complete */
}
<<< ckmrem.c >>>
/*
 * file ckmrem.c
 *
 * Module of MacKermit containing code for remote commands and the display
 * of remote commands.
 *
 */
 
/*
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained. 
*/
 
#include "ckcker.h"
#include "ckmdef.h"			/* General Mac defs */
#include "ckmres.h"			/* Resource file defs */
#include "mac/quickdraw.h"		/* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
 
int isbehind;
 
typedef struct {
  int resid;
  char scode,*name,*hlp1,*hlp2;
} RCMDTBL;
 
RCMDTBL remotecmds[] = {
  {CWD_REMO,  'C',  "CWD",        "Directory",  "Password"},
  {DEL_REMO,  'E',  "Delete",     "Filespec",   ""},
  {DIR_REMO,  'D',  "Directory",  "Filespec",   ""},
  {HELP_REMO, 'H',  "Help",       "Topic",      ""},
  {HOST_REMO, ' ',  "Host",       "Command",    ""},
  {SPAC_REMO, 'U',  "Space",      "Area",       ""},
  {TYPE_REMO, 'T',  "Type",       "Filespec",   ""},
  {WHO_REMO,  'W',  "Who",        "User ID",    "Options"},
  {0,0,NILPTR,NILPTR,NILPTR}};
 

/* Remote command dialog */
 
/*
 * remotedialog - returns FALSE if cancel hit, TRUE otherwise with
 *    	      	  generic command setup in gstr.
 *
 */
 
int remotedialog(rid,gstr)
int rid;
char *gstr;
{
 int itemhit,itemtype,i;
 DialogPtr remoteDialog;
 Handle itemhdl;
 Rect itemrect;
 RCMDTBL *rcmdh = (RCMDTBL *) NULL;
 char arg1[256],arg2[256];
 
 for (i=0; remotecmds[i].resid != 0; i++) /* locate remote command */
  if (remotecmds[i].resid == rid)	/* record for this command */
   rcmdh = &remotecmds[i];		/* set our handle */
 
 if (rcmdh == (RCMDTBL *) NULL)		/* find anything? */
 {
  printerr("Can't find remote command info for ",rid); /* ugh... */
  return(FALSE);
 }
 
 remoteDialog = GetNewDialog(REMOTEBOXID,NILPTR,(WindowPtr) -1);
 ParamText(rcmdh->name,rcmdh->hlp1,rcmdh->hlp2,"");	/* setup variables */
 
 if (strlen(rcmdh->hlp2) == 0)		/* second argument? */
 {					/* no, remove from screen */
  GetDItem(remoteDialog,RRES_ARG2,&itemtype,&itemhdl,&itemrect);
  if (itemtype != editText)
    printerr("RRES_ARG2 is not editText!",0); /* ugh now we die! */
  itemtype |= itemDisable;		/* disable it */
  SetRect(&itemrect,1044,20,1145,116);	/* off the end of our world */
  SetDItem(remoteDialog,RRES_ARG2,itemtype,itemhdl,&itemrect);
 }
 
 ShowWindow(remoteDialog);
 
 for (;;) {
  
   ModalDialog(NILPROC,&itemhit);
   switch (itemhit) {
     case OKBtn:
       GetDItem(remoteDialog,RRES_ARG1,&itemtype,&itemhdl,&itemrect);
       GetIText(itemhdl,arg1);
       GetDItem(remoteDialog,RRES_ARG2,&itemtype,&itemhdl,&itemrect);
       GetIText(itemhdl,arg2);
       if (rid == HOST_REMO)
	strcpy(gstr,arg1);
       else
        setgen(gstr,rcmdh->scode,arg1,arg2,""); /* setup the command */
       
     case QuitBtn:			/* fall through */
       DisposDialog(remoteDialog);	/* all done, answer on cterm screen */
       if (itemhit == OKBtn)		/* want to do the command?/ */
       {
	 conoc(CR);			/* output CR to delimit */
	 conoll("-----");		/* and dashes followed by CR */
         if (isbehind)			/*  response window behind?/ */
	  rcmdwshow();			/*  yes, so show it */
       }
       return(itemhit == OKBtn);	/* and return ok or bad... */
   }
 }
}
 

/* Remote command response window */
 
extern MenuHandle menus[];
 
WindowPtr rcmdwindow;
WindowRecord rcmdwr;
Rect teviewr,dragrect,growrect;
TEHandle teh;
ControlHandle vscroll,hscroll;
Point theorigin;
 
 
/* initrcmdw - ini */
 
initrcmdw() {
WindowPtr oldw;
 
  isbehind = TRUE;			/* from 0 above */
 
  GetPort(&oldw);			/* save old stuff */
  rcmdwindow = GetNewWindow(RCMDBOXID,&rcmdwr,(WindowPtr) 0);
  SetPort(rcmdwindow);			/* set new stuff */  
  
  SetWTitle(rcmdwindow,"Remote Commands");
  SetWRefCon(rcmdwindow,RCD_WREF);	/* setup reference handle */
  
  vscroll = GetNewControl(RCMDVSCROLL,rcmdwindow);
  SetCtlMin(vscroll,0);			/* min is always zero */
  SetCtlMax(vscroll,0);			/* max starts at zero */
  
  hscroll = GetNewControl(RCMDHSCROLL,rcmdwindow);
  SetCtlMin(hscroll,0);			/* min is always zero */
  
  sizescrollbars();			/* make controls adjust to wind size */
  sizeteviewr();			/* resize text edit rect */  
  
  teh = TENew(&teviewr,&teviewr);	/* create text edit portion */
  (*teh)->crOnly = -1;			/* only break lines at CR */
  (*teh)->txFont = monaco;		/* fixed spaced font */
  (*teh)->txSize = 12;			/* 12 pts (big) */
  consette(teh);			/* setup for low lvl console rtns */
  
  theorigin.h = 0;
  theorigin.v = 0;
  SetRect(&dragrect,4,24,508,338);
  SetRect(&growrect,100,60,512,302);
 
  SetPort(oldw);			/* restore old stuff */  
 
}
 
togglercmdw()
{
  if (isbehind)
   rcmdwshow();
  else
   rcmdwhide();
}
 
rcmdwhide()
{
  HideWindow(rcmdwindow);		/* hide it */
  HideControl(vscroll);			/* these will be shown on select */
  HideControl(hscroll);  
  SetItem(menus[REMO_MENU],RESP_REMO,"Show Response");
  isbehind = TRUE;
}
 
rcmdwshow()
{
  ShowWindow(rcmdwindow);		/* show it */  
  BringToFront(rcmdwindow);  
  SelectWindow(rcmdwindow);
  SetItem(menus[REMO_MENU],RESP_REMO,"Hide Response");
  isbehind = FALSE;
}
 
/* rcdactivate - activate event on rcd window */
 
rcdactivate(mod)
{
  WindowPtr oldw;
  
  GetPort(&oldw);
  SetPort(rcmdwindow);
 
  DrawGrowIcon(rcmdwindow);
  if (mod & activeFlag)
  {
/*  TEActivate(teh); */
    ShowControl(vscroll);
    ShowControl(hscroll);
  } 
  else {
/*  TEDeactivate(teh); */
    HideControl(vscroll);
    HideControl(hscroll);
  }
  SetPort(oldw);
}
 
/* rcdmouse - mouse event on rcd window */
 
rcdmouse(wcode,evt)
EventRecord *evt;
{
  int actrlcode,scroll(),t;
  ControlHandle acontrol;
  WindowPtr oldw;
 
  GetPort(&oldw);
  SetPort(rcmdwindow);
 
  switch (wcode) {
    case inDrag:
      DragWindow(rcmdwindow,&evt->where,&dragrect);
      break;
 
    case inGoAway:
      if (TrackGoAway(rcmdwindow,&evt->where))
      	rcmdwhide();			/* put it away */
      break;
 
    case inGrow:
      if (rcmdwindow == FrontWindow())
      	growwindow(rcmdwindow,&evt->where);
      else
      	SelectWindow(rcmdwindow);
      break;
 
    case inContent:
      if (rcmdwindow != FrontWindow())
      {
      	SelectWindow(rcmdwindow);
	break;
      }
 
      GlobalToLocal(&evt->where);	/* convert to local */
      if (PtInRect(&evt->where,&teviewr)) /* in text edit? */
      	break;				/* yes, do nothing */
      actrlcode = FindControl(&evt->where,rcmdwindow,&acontrol);
      switch (actrlcode) {
	case inUpButton:
	  t = TrackControl(acontrol,&evt->where,scroll);
	  break;
	case inDownButton:
	  t = TrackControl(acontrol,&evt->where,scroll);
	  break;
	case inPageUp:
	  pagescroll(actrlcode,-10,acontrol);
	  break;
	case inPageDown:
	  pagescroll(actrlcode,10,acontrol);
	  break;
	case inThumb:
	  t = TrackControl(acontrol,&evt->where,(ProcPtr)NIL);
	  scrollbits();
	  break;
      }
   }   
   SetPort(oldw);			/* back to old space */
}
 
 
growwindow(w,p)
WindowPtr w;
Point *p;
{
  int gr;
  int height,width;
  Rect tmpr;
 
  gr = GrowWindow(w,p,&growrect);
  if (gr == 0)
    return;
  height = HiWord(gr);
  width = LoWord(gr);
 
  SizeWindow(w,width,height,TRUE);	/* size the window */
  sizescrollbars();			/* size the scroll bars */
  sizeteviewr();			/* size for text edit */
  (*teh)->viewRect = teviewr;		/* set it */
  InvalRect(&w->portRect);		/* cause all to be redrawn */
}
 
rcdupdate(w)
WindowPtr w;
{
  ClipRect(&w->portRect);
  EraseRect(&w->portRect);
  DrawGrowIcon(w);
/*  setscrollmax();			/* set our max */
  DrawControls(w);
  TEUpdate(&teviewr,teh);
}
 
scrollbits()
{
  Point oldorigin;
  int dh,dv;
 
  oldorigin = theorigin;
  theorigin.h = GetCtlValue(hscroll);
  theorigin.v = GetCtlValue(vscroll);
  dh = (oldorigin.h - theorigin.h);
  dv = (oldorigin.v - theorigin.v) * (*teh)->lineHeight;
  TEScroll(dh,dv,teh);
}
 
rcdwscroll()
{
 WindowPtr oldw;
 int ctlm;
 
 GetPort(&oldw);
 SetPort(rcmdwindow);			/* our window is the port */
 setscrollmax();			/* set the max */
 SetCtlValue(vscroll,GetCtlMax(vscroll)); /* and set control */
 scrollbits();				/* do scroll */
 SetPort(oldw);				/* back to old port */
}
 
struct tcargs {
  short theCode;
  ControlHandle whichControl;
};
 
scroll()
{
  struct tcargs a;
  register int amount = 0;
 
  getpargs(&a,sizeof a);
  
  if (a.theCode == inUpButton) amount = -1;
  if (a.theCode == inDownButton) amount = 1;
  if (amount == 0) return;
  SetCtlValue(a.whichControl,GetCtlValue(a.whichControl)+amount);
  scrollbits();
}
 
pagescroll(code,amount,ctrlh)
ControlHandle ctrlh;
{
  Point myPt;
 
  do {
      GetMouse(&myPt);
      if (TestControl(ctrlh, &myPt) != code)
      	continue;
      SetCtlValue(ctrlh,GetCtlValue(ctrlh)+amount);
      scrollbits();
     } while (StillDown());
}
 
/* setscrollmax - sets the vertical scroll control's maximum value.
 *    	      	  The max is the total number of lines in the te record
 *    	      	  minus the number of lines that can be displayed in the
 *    	      	  viewing rectangle (plus 1).  This makes the max setting
 *    	      	  of the control result in the display of the last chunk
 *    	      	  of text.
 */
 
setscrollmax()
{
 int maxv;
 
 maxv = (*teh)->nLines + 1 -
     (((*teh)->viewRect.bottom-(*teh)->viewRect.top)/(*teh)->lineHeight);
 if (maxv < 0)				/* for less than one page */
  maxv = 0;				/*  use this value as max */
 SetCtlMax(vscroll,maxv);		/* set it... */
}
 
/* sizescrollbars - called when window is created and after a window grow
 *    	      	    sequence to resize the scroll window's bars.
 */
 
sizescrollbars()
{
  register Rect *r;
  
  r = &rcmdwindow->portRect;		/* window size */
  HideControl(vscroll);
  HideControl(hscroll);
  
/*  setscrollmax();			/* set vertical scroll max */
  MoveControl(vscroll,r->right-15,r->top-1);
  SizeControl(vscroll,16,r->bottom-r->top-13);
 
  MoveControl(hscroll,r->left-1,r->bottom-15);
  SizeControl(hscroll,r->right-r->left-13,16);
  
  ShowControl(vscroll);  
  ShowControl(hscroll);
}
 
sizeteviewr()
{
  teviewr = rcmdwindow->portRect;
  teviewr.left = teviewr.left+4; 
  teviewr.right = teviewr.right-15;
  teviewr.bottom = teviewr.bottom-15;
}
<<< ckmres.h >>>
/* ckmres.h - MAC C Kermit resource file equates */
 
#define RCMDBOXID 1000
#define RCMDHSCROLL 1001
#define RCMDVSCROLL 1000
 
#define ALERT_ERROR 1			/* error aler */
#define ALERT_DEBUG 2			/* debug alert */
#define ALERT_ABORT 3			/* abort protocol */
#define ALERT_FEXIST 4			/* alert: file exists */
 
/* MENUS */
 
#define MIN_MENU 1			/* first menu resource ID  */
 
#define APPL_MENU 1			/* APPLE: */
#define  ABOUT_APL 1			/*  about kermit */
 
#define FILE_MENU 2			/* FILE: */
#define  LOAD_FIL 1			/*  load settings */
#define  SAVE_FIL 2			/*  save settings */
					/*  (- (leave a space) */
#define  GETS_FIL 4			/*  get a file from server */
#define  SEND_FIL 5			/*  send a file */
#define  RECV_FIL 6			/*  receive a file */
					/*  (- (leave a space) */
#define  QUIT_FIL 8			/*  quit this program */
 
#define SETG_MENU 3			/* SETTINGS: */
#define  FILE_SETG 1			/*  file settings */
#define  COMM_SETG 2			/*  communications settings */
#define  PROT_SETG 3			/*  protocol settings */
					/* (- (leave a space) */
#define  SCRD_SETG 5			/*  screen dumping... */
 
#define REMO_MENU 4			/* REMOTE: */
#define  RESP_REMO 1			/*  show/hide response window */
					/* (- (leave a space) */
#define  FIN_REMO 3			/*  finish, exit remote server */
#define  BYE_REMO 4			/*  bye (log out server) */
					/* (- (leave a space) */
#define  CWD_REMO 6			/*  cwd - change working directory */
#define  DEL_REMO 7			/*  delete remote file */
#define  DIR_REMO 8			/*  remote directory */
#define  HELP_REMO 9			/*  remote help */
#define  HOST_REMO 10			/*  arbitrary command */
#define  SPAC_REMO 11			/*  disk usage */
#define  TYPE_REMO 12			/*  type a file */
#define  WHO_REMO 13			/*  who is logged in */
					/* (- */
#define  SERV_REMO 15			/* be a server */
 
#define LAU_MENU 5			/* LAUNCH: */
#define  TOAP_LAU 1			/*  run application */
 
#define MAX_MENU LAU_MENU		/* last menu resource id */
 
/* DLOG 257 - About Kermit */
 
#define ABOUTID 257			/* ID of dialog in resource file */
 
/* DLOG 230 - Status display (during transfer) */
 
#define SCRBOXID 230			/* resource ID for status display */
 
#define SRES_UNDEF 1			/* do nothing guy */
#define  SRES_CANF 1			/* cancel xmit of single file */
#define  SRES_CANG 2			/* cancel xmit of entire group */
#define  SRES_DIR 3			/* "receiving" or "sending" */
#define  SRES_FILN 4			/* filename goes here */
#define  SRES_AS 5			/* "as" or blank */
#define  SRES_AFILN 6			/* as filename or blank */
#define  SRES_KXFER 8			/* numeric for "Kbytes" */
#define  SRES_NPKT 10			/* numeric for "Packets" */
#define  SRES_NRTY 12   		/* numeric for "Retries" */
#define  SRES_FFORK 13			/* "RSRC FORK" or "DATA FORK" */
#define  SRES_FMODE 14			/* "TEXT MODE" or "BINARY MODE" */
#define  SRES_BTEXT 15			/* arbitrary big text */
 
/* DLOG 1001 - Communications setup dialog */
 
#define COMMBOXID 1001			/* resource ID for comm setup */
#define CRES_BAUD300 5
#define CRES_BAUD600 6
#define CRES_BAUD1200 7
#define CRES_BAUD1800 8
#define CRES_BAUD2400 9
#define CRES_BAUD4800 10
#define CRES_BAUD7200 11
#define CRES_BAUD9600 12
#define CRES_BAUD19200 13
#define CRES_BAUD57600 14
 
#define CRES_AUTOWRAPON 16
#define CRES_AUTOWRAPOFF 17
 
#define CRES_PARMARK 19
#define CRES_PARSPACE 20
#define CRES_PAREVEN 21
#define CRES_PARODD 22
#define CRES_PARNONE 23
 
#define CRES_ECHOLCL 25			/* local echo - full duplex */
#define CRES_ECHOREM 26			/* local echo - half duplex */
 
/* DLOG 1002 - Protocol setup dialog */
 
#define PROTOBOXID 1002
 
#define PRES_BLK1 5			/* block check types */
#define PRES_BLK2 6
#define PRES_BLK3 7
 
#define PRES_HSBELL 9			/* hand shake character */
#define PRES_HSCR 10
#define PRES_HSESC 11
#define PRES_HSLF 12
#define PRES_HSNONE 13
#define PRES_HSXON 14
#define PRES_HSXOFF 15
 
#define PRES_INSOP 19			/* start of packet edit text */
#define PRES_INEOP 21			/* end of packet edit text */
#define PRES_INPADC 23			/* pad character edit text */
#define PRES_INPADN 25			/* pad count edit text */
#define PRES_INTIMEO 27			/* seconds timeout edit text */
#define PRES_INPKTLEN 29		/* packet length edit text */
 
#define PRES_OUTSOP 30			/* start of packet edit text */
#define PRES_OUTEOP 31			/* end of packet edit text */
#define PRES_OUTPADC 32			/* pad character edit text */
#define PRES_OUTPADN 33			/* pad count edit text */
#define PRES_OUTTIMEO 34		/* seconds timeout edit text */
#define PRES_OUTPKTLEN 35		/* packet length edit text */
 
/* DLOG 1003 - remote dialog */
 
#define REMOTEBOXID 1003
#define RRES_ARG1 5
#define RRES_ARG2 7
 
<<< ckmsav.c >>>
/* Edit by Frank on Jun 20 17:20 */
/* Don't set sio chip parity */
/* Edit by Bill on May 29 01:01 */
/* Add key configurator */
/* Edit by Bill on May 10 9:24 */
/* Saving settings file to a different disk doesn't work and may bomb */
/* Edit by Bill on May 8 7:17 */
/* Save default file settings, now incompatable with existing save files! */
/* Edit by Bill & Jeff on May 1 14:16 */
/* findfinderfiles was bombing because of fName[1] definition of myAppFile */
/* Edit by Bill on Apr 30 05:50 */
/* Call FlushVol after saving the settings */
 
/* 
 * file ckmsav.c
 *
 * Module of MacKermit containing code for saving and restoring
 * various variables.
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#include "ckcker.h"			/* Kermit definitions */
#include "ckmdef.h"			/* Common Mac module definitions */
#include "ckmres.h"			/* resource defs */
#include "mac/quickdraw.h"
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
#include "ckmkkc.h"			/* common key config defs */
 
char SAVC_TYPE[] = {"SAVC"},		/* rsrc character types */
     SAVI_TYPE[] = {"SAVI"},		/* rsrc integer types */
     MSET_TYPE[] = {"MSET"},		/* meta prefix string */
     FSET_TYPE[] = {"FSET"},		/* function defs */
     KSET_TYPE[] = {"KSET"};		/* key set */
 
#define SVVER 3				/* version & rsrc ID number */
 
char ttype[] = "TEXT";			/* want's to be long aligned */
 
OsType kermtype = {"KERM"};
OsType texttype = {"TEXT"};
 
KSHDL kshdl;				/* handle to kset */
 
int *inames[] = {
  &speed,&parity,&duplex,&delay,
  &mypadn,&npad,&timint,&rtimo,&rpsiz,&spsiz,
  &turnch,&turn,&bctr,&filargs.fildflg
};
 
#define NINAMES (sizeof(inames) / sizeof(int *))
 
char *cnames[] = {
  &mypadc,&padch,&eol,&seol,&stchr,&mystch
};
 
#define NCNAMES (sizeof(cnames) / sizeof(char *))
 

/* privrsrc - return a private copy of a resource.  The handle
 *    	      returned is relocatable but non purgeable.
 *
 */
 
Handle privrsrc(type,id)
char *type;
{
  Handle rhdl,phdl,cpyhdl();
  char errbuf[256];
 
  rhdl = GetResource(type,id);		/* load the resource */
  if (rhdl == (Handle) NIL)		/* nothing? */
  {
    strcpy(errbuf,"There is no resource ");
    strcat(errbuf,type);
    fatal(errbuf,0);			/* real problem guy */
  }
 
  phdl = cpyhdl(rhdl);			/* make private copy */
  ReleaseResource(rhdl);		/* rsrc completely gone now */
  return(phdl);				/* all done */
  SYM(PRIVRESOURCE);
}
 
KSHDL loadkset()
{
 Handle fhdl,mhdl;
 KSHDL khdl;
 
 khdl = (KSHDL) privrsrc(KSET_TYPE,KSVER);
 fhdl = privrsrc(FSET_TYPE,KSVER);
 (*khdl)->fcnshdl = fhdl;		/* save handle to relocatable block */
 mhdl = privrsrc(MSET_TYPE,KSVER);
 (*khdl)->metahdl = mhdl;		/* save handle */
 return(khdl);				/* return the KSET handle */
 SYM(LOADKSET);
}
 

Handle cpyhdl(hdl)
Handle hdl;
{
  Handle nhdl;
  int hsize;
 
  hsize = GetHandleSize(hdl);		/* find size */
  nhdl = NewHandle(hsize);		/* get a new handle */
  if (nhdl == (Handle) NIL)
   fatal("NewHandle failed in cpyhdl: ",0);
   
  HLock(hdl);				/* unlikely */
  HLock(nhdl);				/*  but lock anyway */
  BlockMove(*hdl,*nhdl,hsize);		/* copy contents */
  HUnlock(hdl);
  HUnlock(nhdl);
  HNoPurge(nhdl);			/* is probably default */
  return(nhdl);
  SYM(CPYHDL);
}
 

/* savevals - save variables for MacKermit */
 
typedef int  **IHandle;			/* handle to int[] */
typedef char **CHandle;			/* handle to char[] */
 
savevals()
{
  IHandle ihdl;
  CHandle chdl;
 
  SFReply savr;
  Point where;
  int err,rfnum,i;
  FInfo finf;
 
  SetPt(&where,75,115);
  SFPutFile(&where,"Save variables in file:","",NILPROC,&savr);
  if (!savr.good)			/* did they hit cancel? */
   return;				/* yes, so return now */
  
  SetVol(NILPTR,savr.vRefNum);		/* select volume for rsrc file */
 
  CreateResFile(isapstr(savr.fName)); 	/* try to create */   
  if (ResError() != noErr &&		/* an error occured */
      ResError() != dupFNErr)		/*  but not already exists? */
  {
    printerr("Unknown error from create: ",ResError());
    return;
  }
  
  rfnum = OpenResFile(isapstr(savr.fName));
  if (rfnum == -1)			/* failed to open? */
  {
    printerr("Couldn't Open resource file: ",ResError());
    return;
  }
  
  err = GetFInfo(isapstr(savr.fName),savr.vRefNum,&finf);
  if (err != noErr)
   printerr("Can't get finder info for file: ",err);
  else 
  {
    finf.fdType = texttype;		/* set type */
    finf.fdCreator = kermtype;		/* set creator */
    finf.fdFldr = filargs.filfldr;	/* use same as folder as application */
    err = SetFInfo(isapstr(savr.fName),savr.vRefNum,&finf);
    if (err != noErr)
      printerr("Can't set finder info: ",err);
  }
  
  ihdl = (IHandle) NewHandle(sizeof(inames));
  for (i=0; i < NINAMES; i++)		/* copy from indirect table */
    (*ihdl)[i] = *inames[i];		
  AddResource((Handle) ihdl,SAVI_TYPE,SVVER,"");
  
  chdl = (CHandle) NewHandle(sizeof(cnames));
  for (i=0; i < NCNAMES; i++)		/* copy from indirect table */
    (*chdl)[i] = *cnames[i];
  AddResource((Handle) chdl,SAVC_TYPE,SVVER,"");
  
  AddResource(cpyhdl((*kshdl)->metahdl),MSET_TYPE,KSVER,"");
  AddResource(cpyhdl((*kshdl)->fcnshdl),FSET_TYPE,KSVER,"");
  AddResource(cpyhdl((Handle) kshdl),KSET_TYPE,KSVER,"");
 
  CloseResFile(rfnum);
  FlushVol(NILPTR,savr.vRefNum);	/* flush the bits out */
}
 
/* kfilefilter - match creator "KERM" from sfgetfile call */
 
kfilefilter()
{
 FileParam *pb;				/* args from SFGetFile... */
 char *retval;
 
 retval = (char *) getpargs(&pb,sizeof(FileParam *));
 *retval = (strncmp(			/* compare creator's... and return */
      pb->ioFlFndrInfo.fdCreator.s, 	/* TRUE if not a match */
      kermtype.s,4) != 0);		/* FALSE otherwise for inclusion */
}
 
loadvals()
{
  SFReply savr;
  Point where;
 
  SetPt(&where,75,115);
  SFGetFile(&where,"Load variables from:",
      	    kfilefilter,1,ttype,NILPROC,&savr);
  if (!savr.good)			/* did they hit cancel? */
   return;				/* yes, so return now */
  
 doloadvals(savr.fName,savr.vRefNum);	/* do the load */
}
 
typedef struct {		/* AppFile */
	short	vRefNum;
	OsType	fType;
	short	versNum;
	char	fName[255];		/* used to be fName[1]! */
} myAppFile;
 
findfinderfiles()
{
 int msg,cnt,err;
 myAppFile apf;
 FInfo ainfo;
 
  CountAppFiles(&msg,&cnt);		/* anything clicked by user? */
  if (cnt == 0 || msg == appPrint)	/* or they want us to print (?) */
  {					/* forget about loading values */
   filargs.filfldr = fDesktop;		/* make new files appear on desk */
   kshdl = loadkset();			/* use our default KSET */
   return;
  }
  GetAppFiles(1,&apf);			/*  get the first one */
  ClrAppFiles(1);			/*  done with this */
  doloadvals(apf.fName,apf.vRefNum);	/*  load the file */
  err = GetFInfo(isapstr(apf.fName),	/* get settings file info */
      	      	  apf.vRefNum,&ainfo); 	
  if (err != noErr)
    printerr("Couldn't GetFInfo for default folder: ",err);		  
  filargs.filfldr = ainfo.fdFldr;	/* use appl or text file's folder */
}
 
doloadvals(fn,refnum)
char *fn;
int refnum;
{ 
  int rfnum,i;
  IHandle resinames;
  CHandle rescnames;
 
  SetVol(NILPTR,refnum);		/* select volume */
  rfnum = OpenResFile(isapstr(fn));	/* open the resource file */
  if (rfnum == -1)
  {
    printerr("Couldn't open file: ",ResError());
    return;
  };
  
/* load "SAVI" resource, the saved integer values, "SAVC" saved characters */
 
  if ((resinames = (IHandle) GetResource(SAVI_TYPE,SVVER)) == NIL ||
      (rescnames = (CHandle) GetResource(SAVC_TYPE,SVVER)) == NIL)
  {
   CloseResFile(rfnum);
   printerr("Can't load your settings, damaged file or wrong version.",0);    
   return;				/* and return */
  }
  
  LoadResource((Handle) resinames);	/* load it into memory */
  for (i=0; i < NINAMES; i++)
   *inames[i] = (*resinames)[i];
 
  LoadResource((Handle) rescnames);
  for (i=0; i < NCNAMES; i++)
   *cnames[i] = (*rescnames)[i];
 
  kshdl = loadkset();			/* load new KSET */   
  CloseResFile(rfnum);			/* no longer needed */
  
/* tell serial driver about new vals */
 
  setserial(innum,outnum,speed,KPARITY_NONE);
}
<<< ckmscr.c >>>
/* Edit by Bill on Wed May 15, 15:53 */
/* A K is 1024 not 512 */
 
/*
 * file ckmscr.c
 *
 * Module of mackermit containing code for display of status dialog.
 *
 * Bill Schilit, May 1984 
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#include "ckcker.h"			/* general kermit defs */
#include "ckmdef.h"			/* General Mac defs */
#include "ckmres.h"			/* Mac resource equates */
#include "ckcdeb.h"			/* C kermit debuggig */
#include "mac/quickdraw.h"		/* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
 
int scrpkt,scrnak,scrck;		/* NAK, PKT char (K) counts */
DialogPtr scrdlg = (DialogPtr) NULL;	/* screen's dialog */
 
setitxt(item,str,dlg)
char *str;
DialogPtr dlg;
{
  int itype;
  Handle ihdl;
  Rect ibox;
 
  GetDItem(dlg,item,&itype,&ihdl,&ibox);
  SetIText(ihdl,str);
}
 
/* scrcreate - create the status display.  Called when a protocol
 *    	       menu item is selected and a display is desired (I don't
 *    	       think you'd want to see this for REMOTE command).
 *
 */
 
scrcreate()
{
  char *s;
  
  if (scrdlg != NULL)
   printerr("scrcreate with active screen!",0);
  scrdlg = GetNewDialog(SCRBOXID,NILPTR,(WindowPtr) -1);
  scrck = scrnak = scrpkt = 0;
  setitxt(SRES_DIR,
      	  (protocmd == SEND_FIL) ? "   Sending" : "Receiving",scrdlg);
  ShowWindow(scrdlg);
  miniparser(TRUE);			/* keep things moving */
}
 
#define getctlhdl(item,dp) (ControlHandle) gethdl(item,dp)
 
/* scrdispose - called to finish up the status display, on a 
 *    	      	transaction complete screen() call. 
 */ 
 
scrdispose()
{
  if (scrdlg == NULL)
   printerr("scrdispose called with no screen active!",0);
  SysBeep(1);
  HiliteControl(
      getctlhdl(SRES_CANF,scrdlg),255);	/* deactivate buttons */
  HiliteControl(
      getctlhdl(SRES_CANG,scrdlg),255);	/* ... */
      
  while (!Button());			/* just wait for click */   
  DisposDialog(scrdlg);
  scrdlg = NULL;
}
 

/* ststrings - translation of SCR_ST subfunctions to descriptive text */
 
char *ststrings[] = {
  "Transferred OK",			/* ST_OK */
  "Discarded",				/* ST_DISC */
  "Interrupted",			/* ST_INT */
  "Skipped ",				/* ST_SKIP */
  "Fatal error"				/* ST_ERR */
};
 
/* scrtosresnum - table to translate from SCR_XXX values into resource
 *    	       	  item numbers.  Entries we aren't interested in are 
 *    	          set to SRES_UNDEF.
 */
 
short scrtoresnum[] = { 
    SRES_UNDEF,				/* 0 - nothing */      
    SRES_FILN,				/* SCR_FN - filename */
    SRES_AFILN,				/* SCR_AN - as filename */
    SRES_UNDEF,				/* SCR_FS - file size */
    SRES_UNDEF,				/* SCR_XD - x-packet data */
    SRES_BTEXT,				/* SCR_ST - status */
    SRES_UNDEF,				/* SCR_PN - packet number */
    SRES_UNDEF,				/* SCR_PT - packet type (special) */
    SRES_BTEXT,				/* SCR_TC - transaction complete */
    SRES_UNDEF,				/* SCR_EM - error msg (does alert) */
    SRES_UNDEF,				/* SCR_WM - warning message */
    SRES_BTEXT,				/* SCR_TU - arb text */
    SRES_BTEXT,				/* SCR_TN - arb text */
    SRES_BTEXT,				/* SCR_TZ - arb text */
    SRES_BTEXT 				/* SCR_QE - arb text */
};
    
 

/* screen - display status information on the screen during protocol.
 *    	    Here we just set the items in their StatText dialog boxes,
 *    	    updates occur through the miniparser, which we are nice
 *    	    enough to call here to handle things.
 *
 */
 
screen(f,c,n,s)
int f;
char c,*s;
long n;
{
 int rnum,i;
 int itype;
 Handle ihdl;
 Rect ibox;
 char buf[256];
 
  miniparser(TRUE);			/* keep the mac going */
 
  if (f == SCR_EM || f == SCR_WM)	/* error/warning message? */
  {
    printerr(s,0);			/* display it */
    return;				/* and return */
  }
 
  if ((scrdlg == NULL) || quiet)	/* not using it or silent? */
    return;				/* but nothing for us to do */
 
  if (f == SCR_FN)			/* seeing a file name? */
  {
    setitxt(SRES_AFILN,"",scrdlg);	/* and the name also */
    if (protocmd == RECV_FIL ||		/* seeing a file name from */
        protocmd == GETS_FIL) 		/*  a receive command? */
      dorecvdialog(s,&cmarg2);		/* yes, allow user to do dialog */
  }
  
  rnum = scrtoresnum[f];		/* load default DITL number */
					/*  where result will be posted */
 
  switch (f) {				/* according to function... */
    case SCR_AN:			/* "AS" name is comming */
      setitxt(SRES_FFORK,
      	      (filargs.filflg & FIL_RSRC) ? 
	      "RSRC Fork" : "Data Fork",scrdlg);
      setitxt(SRES_FMODE,	      
      	      (filargs.filflg & FIL_BINA) ? 
	      "Binary Mode" : "Text Mode",scrdlg);
      break;
 
    case SCR_PT:			/* packet type? */
      if (c == 'Y')
        return;				/* don't do anything for yaks */
      if (c == 'N' || c == 'Q' ||	/* check for all types of */
      	  c == 'T' || c == '%')		/*  NAK */
	i = ++scrnak, rnum = SRES_NRTY;	/* increment nak counter */
      else
        i = ++scrpkt,rnum = SRES_NPKT; 	/* else increment pkt counter */
      NumToString(i,buf);		/* translate to number */      
      s = buf;				/* new buffer */
      break;				/* all done */
 
    case SCR_ST:			/* status */
      s = ststrings[c];			/* use subfunction description */
      if (c == ST_SKIP)			/* if skipped... */
      {
	strcpy(buf,"Skipping ");	/* there is something else */
	strcat(buf,s);			/* add in filename */
	s = buf;
      }
      break;
 
     case SCR_TC:			/* transaction completed */
      if (!server)			/* are we a server? */
      {
	scrdispose();			/* no dispose the screen */
	return;				/* and we are done */
      }
      s = "Server transaction complete";
      break;
  }
  
  if (rnum != SRES_UNDEF)		/* have DITL number for this? */
   setitxt(rnum,s,scrdlg);		/* yes, so set the text */
   
  if ((i = ffc/1024) != scrck)		/* more K's xmitted (or new val)? */
  {
    scrck = i;				/* remember new value */
    NumToString(scrck,buf);		/* convert to number */
    if (filargs.filsiz != 0)		/* know the size? (only local) */
    {
      strcat(buf,"/");			/* make it be a fraction */
      NumToString(filargs.filsiz/1024, 	/* figure this one out */
      	  (char *) buf+strlen(buf));
    }	  
    setitxt(SRES_KXFER,buf,scrdlg);	/* set new value */
  }
}
 

/* scrmydlg - handle dialog events occuring in the screen (status)
 *    	      dialog.  Called by the miniparser when a dialog event
 *    	      occurs and we are supposed to handle it.
 */
 
scrmydlg(item)
int item;
{
  switch (item) {
    case SRES_CANF:
      cxseen = TRUE;
      break;
    case SRES_CANG:
      czseen = TRUE;
      break;
  }
}
 
<<< ckmsfp.c >>>
/* Edit by Bill on Wed May 15, 15:48 */
/* change name of rtol to sfprtol, make it the common file rtol rtn */
/* either use RSRC & BINA if .RSRC extension, or use current defaults */
/* Edit by Bill on Wed May 15, 15:48 */
/* in initfilerecv make sure kermit flag binary is set */
 
/* 
 * file ckmsfp.c
 *
 * Module of MacKermit containing standard file package calls:
 *
 *    dosenddialog() - Send file...
 *    dorecvdialog() - Receive file...
 *    dogetfdialog() - Get file from server...
 *
 * Bill Schilit, May, 1984
 *
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 * 
 */
 
#include "ckcker.h"			/* Kermit definitions */
#include "ckmdef.h"			/* Common Mac module definitions */
#include "ckmres.h"			/* resource defs */
#include "mac/quickdraw.h"
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
 
FILINF filargs;				/* is global */
 
typedef struct {			/* SFPGetFile event filter */
  DialogPtr dlg;			/* (in stack order) */
  short item;
} SFdlgFilterArgs;
 
typedef struct {			/* SFPGetFile item hit filter  */
    short *itemhit;			/* (in stack order) */
    EventRecord *theevent;    
    DialogPtr thedialog;
 } ModalFilterArgs;
 

#define DLG_GETF 3998			/* SFPutFile DLOG replacement */
#define DLG_RECV 3999			/* SFPutFile DLOG replacement */
#define DLG_SEND 4000			/* SFGetFile DLOG replacement */
#define DLG_FSET 1004			/* File settings */
 
/* Resource IDs for DLG_GETF DITL (3998) */
 
#define GETF_GETB OK			/* "Get" button */
#define GETF_REMF 4			/* remote file name */
 
/* Resource IDs for DLG_RECV DITL (3999) */
 
#define RECV_RBTN putSave		/* "Receive" button */
#define RECV_PROC 15			/* proceed without more dialogs */
 
#define RADITM_DATA 11
#define RADITM_RSRC 12
#define RADITM_TEXT 13
#define RADITM_BINA 14
 
#define RADITM_FIRST RADITM_DATA
#define RADITM_LAST RADITM_BINA
 
int radflgs[] = {FIL_DATA,FIL_RSRC,FIL_TEXT,FIL_BINA};
int radnotflgs[] = {FIL_RSRC,FIL_DATA,FIL_BINA,FIL_TEXT};
 
/* Resource IDs for DLG_SEND DITL (4000) */
 
#define SEND_ASFN 17			/* "As" file name */
#define SEND_INVT 16			/* invisible edit text */
 
/* Globals used by SEND dialog */
 
SFReply sfr;				/* holds file info */
BOOL sendselflg,			/* TRUE means file was selected */
     sendasflg;				/* TRUE means AS field is active */

/* gethdl - return a control handle given a resource ID */
 
Handle gethdl(item,dp)
DialogPtr dp;
{
 int itype;
 Rect ibox;
 Handle ihdl;
 
 GetDItem(dp,item,&itype,&ihdl,&ibox);
 return(ihdl);
}
 
#define getctlhdl(item,dp) (ControlHandle) gethdl(item,dp)
 
/* setfilflgs - Manage the filflg word and radio controls.
 *
 * Flags will be changed when the resource ID of item hit (passed to
 * this routine) is one of the radio items, or alternately routines can
 * modify the filflg word itself and the radio items will be updated
 * accordingly.
 *
 * N.B. Each dialog using these flags has them defined with the same
 * DITL item numbers.
 *
 */
 
setfilflgs(item,dlg)
DialogPtr dlg;
{
 ControlHandle ctlhdl;
 int i;
 
  if (item >= RADITM_FIRST &&		/* check for item... is it  */
      item <= RADITM_LAST)		/*  a radio item for us? */
  {
    filargs.filflg |= radflgs[item-RADITM_FIRST];	/* yes... set flag */
    filargs.filflg &= ~radnotflgs[item-RADITM_FIRST];  /* clear opposite */
  }
 
  for (i=RADITM_FIRST; i <= RADITM_LAST; i++) /* update all */
  {  
    ctlhdl = getctlhdl(i,dlg); 		/* get a handle on his radio item */
    SetCtlValue(ctlhdl,
        (filargs.filflg & radflgs[i-RADITM_FIRST]) ? btnOn : btnOff);
  }
}
 
setfilnams(remfid,dlg)
DialogPtr dlg;
{
  filargs.filrem[0] = 0;		/* no remote file */
 
  p2cstr(sfr.fName);			/* convert to c */
  strcpy(filargs.fillcl,sfr.fName);	/* copy sfr into local name stg */
  c2pstr(sfr.fName);			/* back into pascal string */
    
  if (remfid != 0)			/* fetch remote name if present */
   GetIText(gethdl(remfid,dlg),filargs.filrem);	/* in an edittext field */
  
  binary = (filargs.filflg & FIL_BINA); /* selected binary mode? */
}

/* sendmydlg - SFPGetFIle item hit filter for "send file" dialog.
 *
 * This filter is called by SFPGetFile to let the programmer handle hits
 * on his custom items.  Our items are 2 sets of buttons for selecting
 * the fork (data or resource) and the transfer mode (binary or text).
 * Also we have an EditText item for filling in the AS name.
 *
 * The buttons are set when the user clicks, but they also are given
 * values depending on the selection of a file.  If the file's type is
 * "APPL" then controls "Resource" and "Binary" are automaticlly set,
 * otherwise the controls "Data" and "Text" are set.  SF-File keeps the
 * SFReply upto date when a file name is selected, but...  unfortunately
 * we are called before the SFReply is updated and so when we notice
 * "getNmList" is hit we defer our update for one cycle.
 *
 * Our other item, the TextEdit item to set the "AS" file name, can be
 * enabled or disabled to allow the selection of a file name by typing a
 * character (standard SFGetFile stuff).  By using the global flag
 * sendasflg and an event filter we switch between sending the chars to
 * SF-File for filename selection and to ModalDialog for TextEdit of our
 * AS name.  Since it would be nice to get rid of that blinking cursor
 * in the TextEdit item our DITL has an invisible EditText item which
 * becomes active for this purpose. 
 *
 * At startup the AS field is disabled (the invisible EditText is
 * current and sndasflg is FALSE).  The user can make AS active by
 * clicking in it.  The user can toggle by clicking on the StatText
 * "AS" -- though I won't tell anybody if you don't.
 *
 */
 
sendmydlg()
{
 SFdlgFilterArgs args;
 short *rslt;
 BOOL isappl;				/* file is an application */
 
 rslt = (short *) getpargs(&args,sizeof(args));
 
 if (sendselflg)			/* file name selection occured? */
 {
   sendselflg = FALSE;			/* yes, don't do this again */
  
   p2cstr(sfr.fName);
   zltor(sfr.fName,filargs.filrem);	/* convert to remote form */
   SetIText(gethdl(SEND_ASFN,args.dlg),	/* display converted name */
      	    filargs.filrem);		/*  in "As" field */
   c2pstr(sfr.fName);			/* back to pascal form */
   setfilnams(SEND_ASFN,args.dlg); 	/* set file names since double */    
					/*  clicking fouls us */
 
   filargs.filflg &= ~FIL_RBDT;		/* turn off all of our flags */
   isappl = (strncmp(sfr.ftype.s,"APPL",4) == 0); /* application? */
   filargs.filflg |= (isappl) ?		/* update flags */
      	  (FIL_RSRC | FIL_BINA) :	/* application */
	  (FIL_DATA | FIL_TEXT);	/* not application */
 }
 
 switch (args.item) {			/* according to the item */
  
  case getNmList:			/* user hit file name */
  
    if (sendasflg)			/* "As" active? */
    {					/* yes... */
      sendasflg = FALSE;		/* deactivate "As" name */
      SelIText(args.dlg,SEND_INVT,0,256); /* activate invisible editText  */
    }
    sendselflg = TRUE;			/* next time around set buttons */
    break;				/* nothing more to do in this pass */
 
  case SEND_ASFN:			/* hit EditText for "AS" */
    sendasflg = TRUE;			/* let modal filter pass to us */
    break;
 
  case getOpen:				/* done? */
    setfilnams(SEND_ASFN,args.dlg); 	/* set file names */
    break;				/* done... */
 }
 setfilflgs(args.item,args.dlg);	/* check for and handle radio items */
 
 *rslt = args.item;			/* pass item back */
}
  

/* sendfilter - SFPGetFile event filter for "send file" dialog.
 *
 * This filter is the same form as a ModalDialog filter, it is used
 * internally by SFPGetFile's ModalDialog call.  Our filter allows the
 * user to select a file by typing the first character, which is a
 * normal function of SFGetFile but is broken when we use EditText in
 * our customized SFGetFile box.  Return 0x1000+char in itemhit to
 * SFGetFile instead of letting ModalDialog handle it with a call to
 * TextEdit.  Using a global flag "sendasflg" we decide to send the
 * character to TextEdit via ModalDialog, or to SFGetFile.
 *
 */
 
sendfilter()
{
 ModalFilterArgs args;
 BOOL *retval;				/* returned value */
 
 retval = (BOOL *) getpargs(&args,sizeof(args));
 
 *retval = FALSE;			/* default is to left Modal handle */
 if (args.theevent->what == keyDown)	/* key down? */
  if (!sendasflg)			/*  and the text isn't selected? */
  {					/* then use as file name selector */
    *args.itemhit = 0x1000 +		/* return char+0x1000 to */
      (args.theevent->message & 0x7f); 	/*  SFPGetfile... */
    *retval = TRUE;			/* let SFP handle it, not modal */
  }
}
 

/* recvmydlg - SFPPutFile item filter for "receive file" dialog.
 *
 *
 */
 
recvmydlg()
{
 SFdlgFilterArgs args;
 short *rslt;
 
 rslt = (short *) getpargs(&args,sizeof(args));
 *rslt = args.item; 
 
 switch (args.item) {
   case RECV_PROC:
     filargs.filflg &= ~FIL_DODLG;	/* no more dialogs for me! */  
     *rslt = RECV_RBTN;			/* did "OK" */
   case RECV_RBTN:
     setfilnams(0,args.dlg);		/* set names */   
     break;
  }
  setfilflgs(args.item,args.dlg);	/* check for and handle radios */
}
 
 
/* dosenddialog - Use SFPGetFile to fetch a file to send. */
 
short recvpt[] = {75,100};
short sendpt[] = {75,80};
 
dosenddialog(lclf,remf)
char *lclf[],*remf[];
{
 filargs.filflg = 0; 
 sendasflg = FALSE;			/* "AS" starts off inactive */
 sendselflg = TRUE;			/* need to update file buttons */
 sfr.fName[0] = 0;			/* clear our old stuff */
 SFPGetFile((Point *) sendpt,"",NILPROC,0, /* all file types, 2 filters */
      	    NILPTR,sendmydlg,&sfr,DLG_SEND,sendfilter);
 *lclf = filargs.fillcl;
 *remf = filargs.filrem;
 filargs.filvol = sfr.vRefNum;		/* remember volume number */  
 return(sfr.good);			/* pass back return */
} 
 
 
dorecvdialog(fn,lclf)
char *lclf[],*fn;
{
  int err;
 
  if (!(filargs.filflg & FIL_DODLG))	/* don't want to do dialogs? */
  {
   *lclf = "";				/* then use a null string */
   return;				/* and return now */
  }
 
  for (;;) {				/* keep trying */
    filargs.filflg &= ~(FIL_RBDT); 	/* clear file modes */
    filargs.filflg |= sfprtol(fn);	/* convert fn and set modes */
    SFPPutFile((Point *) recvpt,"Receive as:",fn,
      	      	recvmydlg,&sfr,DLG_RECV,NILPROC);
    *lclf = filargs.fillcl;
    filargs.filvol = sfr.vRefNum;	/* remember volume number */
    if (!sfr.good) {			/* CANCEL */
      cxseen = TRUE;			/* indicate cancel */
      return;
    } else {
      err = FSDelete(filargs.fillcl,filargs.filvol); /* delete if there */
      if (err == fnfErr)  		/* everything ok? */
        return;				/* yes, return now */
    }
    if (ioutil(err)) return;		/* until no error */
  }
}
 

/* setfiledialog - enter file settings dialog. */
 
#define FSET_ATTEND 4
#define FSET_UNATTEND 5
#define FSET_SUPERSEDE 6
#define FSET_NEWNAMES 7
 
setradpair(rid1,rid2,bool,dlg)
DialogPtr dlg;
{
  SetCtlValue(getctlhdl(rid1,dlg),bool ? btnOn : btnOff);
  SetCtlValue(getctlhdl(rid2,dlg),bool ? btnOff : btnOn);
}
  
setfiledialog()
{
  DialogPtr setfdlg;
  int item;
 
  setfdlg = GetNewDialog(DLG_FSET,NILPTR,(WindowPtr) -1);
  filargs.filflg = filargs.fildflg;	  /* use current defaults */
  ShowWindow(setfdlg);			  /* show it */
  
  for (;;) {
    setfilflgs(item,setfdlg);		  /* keep flags upto date */
    
    setradpair(FSET_ATTEND,FSET_UNATTEND,
      	      (filargs.filflg & FIL_DODLG),setfdlg);
    setradpair(FSET_SUPERSEDE,FSET_NEWNAMES,
      	      (filargs.filflg & FIL_OKILL),setfdlg);
	
    ModalDialog(NILPROC,&item);
    switch (item) {
      case OK:
      	filargs.fildflg = filargs.filflg; /* set default flags */
      case Cancel:
      	DisposDialog(setfdlg);		  /* all done with dialog */
	return;				  /* can go home... */
 
      case FSET_ATTEND:
      case FSET_UNATTEND:
      	filargs.filflg ^= FIL_DODLG;	/* toggle flag */
	break;
	
      case FSET_SUPERSEDE:
      case FSET_NEWNAMES:
      	filargs.filflg ^= FIL_OKILL;	  /* toggle flag */
	break;	
    }
  }    
}
 
initfilrecv()
{
  filargs.filflg = filargs.fildflg;	/* default flags are active */
  warn = !(filargs.filflg & FIL_OKILL);	/* set kermit flag */
  binary = (filargs.filflg & FIL_BINA); /* selected binary mode? */  
  filargs.filsiz = 0;			/* no known size */
}
 
initfilset()
{
  filargs.filvol = 0;			/* default volume is always default */
  filargs.fildflg = FIL_DATA | FIL_TEXT;  /* default file setting */
					  /*  if no settings file */
}  

dogetfdialog(remf)
char *remf[];
{
 DialogPtr getfdlg;
 ControlHandle getbhdl;
 Handle remfhdl;
 int item;
 
 getfdlg = GetNewDialog(DLG_GETF,NILPTR,(WindowPtr) -1);
 
 remfhdl = gethdl(GETF_REMF,getfdlg);
 getbhdl = getctlhdl(GETF_GETB,getfdlg);
 HiliteControl(getbhdl,255);		/* start with deactive Get button */
 
 ShowWindow(getfdlg);
 for (;;) {
   ModalDialog(NILPROC,&item);
   switch (item) {
     case OK:
       if (filargs.filrem[0] == '\0')	/* no file name? */
         break;				/* then they hit CR, don't allow */
       *remf = filargs.filrem;		/* fill in for return */     
       initfilrecv();			/* init recv flags */
     case Cancel:
       DisposDialog(getfdlg);
       return(item == OK);
     case GETF_REMF:
       GetIText(remfhdl,filargs.filrem);
       HiliteControl(getbhdl,(filargs.filrem[0] == 0) ? 255 : 0);
       break;		 
    }
  }   
}
 
/* sfprtol - translate remote file name to a local file name and
 *    	  and figure out the flags as well.
 */
 
#define RSXLEN 5			/* ".rsrc" length */
 
int sfprtol(fn)
char *fn;
{
  int l;
 
  if ((l = strlen(fn)) > RSXLEN &&	/* big enough? */
      (strcmp(&fn[l-RSXLEN],".rsrc") == 0 || /* and matches extension? */
       strcmp(&fn[l-RSXLEN],".RSRC") == 0))  /* either way? */
  {      
   fn[l-RSXLEN] = '\0';			/* so remove the extension */
   return(FIL_BINA | FIL_RSRC);		/* want rsrc and binary */
  }
  return(filargs.fildflg & FIL_RBDT);	/* else return default */
}
<<< ckmsum.c >>>
/* 
 * file ckmsum.c
 *
 * Module of MacKermit containing MACTRAP calls, currently only one, 
 * mygetitem which replaces getitem when dealing with DA names.  
 *
 * The routine GetItem converted the menu item from a pascal to a C
 * string, this made it very hard to deal with DA names which have
 * imbedded nulls.  You could get DA names with NULLs working, or
 * DA names without NULLs working (like the switcher) but you couldn't
 * get them both working.
 *
 * 
 * Copyright (C) 1985, Trustees of Columbia University in the City of
 * New York.  Permission is granted to any individual or institution to
 * use, copy, or redistribute this software so long as it is not sold
 * for profit, provided this copyright notice is retained.
 *
 */
 
#include "mac/quickdraw.h"
#undef h
#undef v
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/libmac.h"
 
/*ARGSUSED*/
void mygetitem(m,i,s)
MenuHandle m; 
char *s;
{
  _mact3(RN,0xa946,N,L,S,L);		/* return L not VPS */
}
<<< ckmtio.c >>>
/*  C K M T I O  --  interrupt, console, and port functions for Mac Kermit  */
 
/*
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained. 
*/
 
/*
 Variables:
 
   dftty  -- Pointer to default tty name string, like "/dev/tty".
   dfloc  -- 0 if dftty is console, 1 if external line.
   dfprty -- Default parity
   dfflow -- Default flow control
   ckxech -- Flag for who echoes console typein:
     1 - The program (system echo is turned off)
     0 - The system (or front end, or terminal).
   functions that want to do their own echoing should check this flag
   before doing so.
 
 Functions for assigned communication line (either external or console tty):
 
   ttopen(ttname,local,modem) -- Open the named tty for exclusive access.
   ttclos()                -- Close & reset the tty, releasing any access lock.
   ttpkt(speed,flow)       -- Put the tty in packet mode and set the speed.
   ttvt(speed,flow)        -- Put the tty in virtual terminal mode.
   ttinl(dest,max,timo)    -- Timed read line from the tty.
   ttinc(timo)             -- Timed read character from tty.
   ttchk()                 -- See how many characters in tty input buffer.
   ttxin(n,buf)            -- Read n characters from tty (untimed).
   ttol(string,length)     -- Write a string to the tty.
   ttoc(c)                 -- Write a character to the tty.
   ttflui()                -- Flush tty input buffer.
 
Functions for console terminal:
 
   congm()   -- Get console terminal modes.
   concb()   -- Put the console in single-character wakeup mode with no echo.
   conbin()  -- Put the console in binary (raw) mode.
   conres()  -- Restore the console to mode obtained by congm().
   conoc(c)  -- Unbuffered output, one character to console.
   conol(s)  -- Unbuffered output, null-terminated string to the console.
   conxo(n,s) -- Unbuffered output, n characters to the console.
   conchk()  -- Check if characters available at console.
   coninc()  -- Get a character from the console.
   conint()  -- Enable terminal interrupts on the console.
   connoi()  -- Disable terminal interrupts on the console.
   
Time functions
 
   msleep(m) -- Millisecond sleep
   ztime(&s) -- Return pointer to date/time string
*/

#include "ckcdeb.h"			/* Formats for debug() */
#include "ckmdef.h"			/* macintosh defs */
#include "mac/quickdraw.h"
#include "mac/osintf.h"
#include "mac/toolintf.h"		/* TE types defined here */
 
char *dftty = "";
 
/* dfloc is 0 if dftty is the user's console terminal, 1 if an external line */
 
int dfloc = 1;
 
/* Other defaults */
 
int dfprty = 0;				/* No parity */
int dfflow = 1;				/* Xon/Xoff flow control */
 
/* buffer and pointer for input processing */
 
#define TTBUFL 200			/* good size (it's RBUFL guys!) */
unsigned char ttbuf[TTBUFL+1];
int ttbufi = 0,
    ttbufm = 0;				/* input pointer, max */
 

/*  S Y S I N I T  --  System-dependent program initialization.  */
 
sysinit() {
 
/* for now, nothing... */
    return(0);
}

/*  T T O P E N  --  Open a tty for exclusive access.  */
 
/*  Returns 0 on success, -1 on failure.  */
 
ttopen(ttname,lcl,modem) char *ttname; int *lcl, modem; {
  ttbufi = ttbufm = 0;			/* init buffer */
  if (*lcl < 0) *lcl = 1;		/* always in local mode */
  return(0);
}
 
 
/*  T T C L O S  --  Close the TTY, releasing any lock.  */
 
ttclos()
{
  ttbufi = ttbufm = 0;			/* init buffer */  
  return;
}

/*  T T P K T  --  Condition the communication line for packets. */
 
/*  If called with speed > -1, also set the speed.  */
 
/*  Returns 0 on success, -1 on failure.  */
 
ttpkt(speed,flow)
int speed, flow;
{
    return(0);
}

/*  T T F L U I  --  Flush tty input buffer */
 
ttflui()
{
  int err;
 
  err = KillIO(-6);
  if (err)
    printerr("Bad input clear",err);
  ttbufi = ttbufm = 0;			/* init buffer */      
  return(0);
}
 

/* Interrupt Functions */
 
/* Set up terminal interrupts on console terminal */
 
conint(f)
int (*f)();
{					/* Set an interrupt trap. */
    return;
}
 
/* Reset console terminal interrupts */
 
connoi()
{
    return;
}

/*  T T O L  --  Similar to "ttinl", but for writing.  */
 
ttol(s,n)
char *s;
int n;
{
    int err;
    PLONG wrcnt;			/* pascal long */
 
    wrcnt = n;
    err = FSWrite(outnum,&wrcnt,s);
    if (err) printerr("Bad Writeout:",err);
    return(n);
}
 
 
/*  T T I N L  --  Read a record (up to break character) from comm line.  */
/*
  If no break character encountered within "max", return "max" characters,
  with disposition of any remaining characters undefined.  Otherwise, return
  the characters that were read, including the break character, in "dest" and
  the number of characters read as the value of function, or 0 upon end of
  file, or -1 if an error occurred.  Times out & returns error if not completed
  within "timo" seconds.
*/
 
 
ttinl(dest,max,timo,eol)
int max, timo;
char *dest, eol;
{
    register int x,c;
 
    for (x = c = 0; (x < max) && (c != eol); x++)
    {
      dest[x] = c = ttinc(timo);
      if (c < 0)
       return(-1);			/* timeout */
    }
    return(++x);			/* else return the count. */
}
 
/* ttinc(timo) - read a character with timeout.  Return -1 on timeout. */
 
/* DELAYTICKS is the dismiss value in 60th of a second when the input */
/* buffer goes empty.  Setting this value too small causes more overhead */
/* since we'll get very few character on the read.  Setting this value */
/* too large causes a slowdown if characters are on their way... */
 
#define DELAYTICKS 15			/* 15/60th of second retry */
 
ttinc(timo)
int timo;
{
 
    int avcnt, finaltics, intim=0, err;
  
    if (ttbufi < ttbufm) return(ttbuf[ttbufi++]);   /* Return char quickly */
     
/* Refill buffer with available bytes, if none left retry until timo */
 
    for (;;)
    {
	SerGetBuf(innum,&avcnt);	/* Get available count */        
	if (avcnt > 0)			/* Have something? */
	{
	    ttbufi = 0;			/* Init input buffer ptr */
	    ttbufm = (avcnt > TTBUFL) ? TTBUFL : avcnt; /* Set max */
	    err = FSRead(innum,&ttbufm,ttbuf);	/* Into our buffer */
	    if (err != noErr) printerr("Serial input error: ",err);
	    return(ttbuf[ttbufi++]);	/* And return first character */
	}
	if (protocmd != 0)		/* if we're running protocol */
	{
	  miniparser(TRUE);		/* keep mac running */
	  if (sstate == 'a')		/* abort occured? */
	   return(-1);			/* ugh, look like timeout */
	}
	Delay(DELAYTICKS,&finaltics);	/* Delay for a little */
	if (timo > 0)			/* Want to do timeout? */
	{				/* Yes... */
	    if (intim == 0)		/* Do we know time in? */
	    	intim = finaltics - DELAYTICKS;	/* no, initialize it */
	    if (intim+timo*60 < finaltics) return(-1);	/* Too long, give up */
	}
    }
}
 
ttchk()
{
  PLONG avcnt;				/* pascal long */
 
  SerGetBuf(innum,&avcnt);		/* get available */
  return(avcnt+(ttbufm-ttbufi));	/* return avail plus our own */
}
 
ttres()
{
    return(1);
}

/*  R T I M E R --  Reset elapsed time counter  */
 
rtimer() {
}
 
 
/*  G T I M E R --  Get current value of elapsed time counter in seconds  */
 
gtimer() {
    return(0);
}
 
 
/*  Z T I M E  --  Return date/time string  */
 
ztime(s)
char **s;
{
/***** Should call GetTime(daterec); and then convert by hand to a string */
 
    *s = "Unknown date/time";
}

/* Console IO routines.  The console is implemented as a text edit structure.
 * These routines are supported:
 *
 * conoc(c)   -- output one character to TE record at insertion point
 * conol(s)   -- output null terminated string to TE record " "
 * conoll(s)  -- same but with CR on the end 
 * conxo(n,s) -- n character to TE record " "
 *
 */
 
#define NILTE ((TEHandle ) NILPTR) 
#define LF 012
#define CR 015
 
TEHandle consoleTE = NILTE;		/* storage for console TE ptr */
 
consette(t)
TEHandle t;
{
  
 if (consoleTE != NILTE)		/* already have TE record */
  printerr("TE record present at consette! ",0);
 consoleTE = t;
}
 
/*  C O N O C  --  Output a character to the console text edit record */
 
conoc(c)
char c;
{
 int len = 1;
 
 debug(F101,"conoc here: ","",c);
 
 if (c == LF)				/* we don't support this */
  return;
 if (consoleTE != NILTE)		/* is it present? */
 {
/*  TEKey(c,consoleTE);			/* yes, simple */
  TEInsert(&c,len,consoleTE);		/* insert the char */  
  if (c == CR)				/* if CR */
   rcdwscroll();			/* then possibly scroll it */
 }
}
 
conopen()
{
 if (consoleTE == NILTE)
  printerr("Tried to open console before TE set",0);
 return(0);
}
 
 
/*  C O N O L  --  Write a line to the console text edit record  */
 
conol(s)
char *s;
{
  int len = strlen(s);			/* fetch length */
  
 debug(F101,"conol here: ",s,0);  
 if (consoleTE != NILTE)		/* is it present? */  
  TEInsert(s,len,consoleTE);		/* insert the string */
 return(0);
}
 
conxo(s,len)
char *s;
{
 debug(F101,"conxo here: ",s,len);    
 if (consoleTE != NILTE)		/* is it present? */  
  TEInsert(s,len,consoleTE);		/* insert the string */
 return(0);
}
 
/*  C O N O L L  --  Output a string followed by CRLF  */
 
conoll(s)
char *s;
{
  conol(s);				/* first the string */
  conoc(CR);				/* now the return */
  return(0);
}
 
<<< ckmusr.c >>>
/* DPVC at U of R, on Oct 1, to do blinking cursor and mouse cursor movement */
/* Edit by Bill, Jeff, and Howie on Jun 13 */
/* Add select window, drag */
/* Edit by WBC3 on Apr 29 */
/* Don't supply a second name for send as, otherwise file name translation */
/* will not occur.  Let user type it if they want. */
/* Edit by WBC3 on Apr 23 */
/* Make typein to the emulator only take effect when it's the "front window" */
/* Edit by WBC3 on Apr 23 */
/* Make only Command-. stop protocol rather then anything but Command-. */
/* Edit by WBC3 on Apr 22 */
/* Make debug and tlog only show up if DEBUG is defined */
/* Edit by Bill on Apr 21 17:51 */
/* In Screen depelete event queue instead of handling one event at */
/* a time, also don't loose events */
 
/*
 * file ckmusr.c
 *
 * Module of mackermit containing code for the menus and other MacIntosh
 * things.
 *
 */
 
/*
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained.
*/
 
#include "ckcker.h"
#include "ckmdef.h"                     /* General Mac defs */
#include "ckmres.h"                     /* Mac resource equates */
#include "ckcdeb.h"
#include "mac/quickdraw.h"              /* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
#include "ckmkkc.h"                     /* keyboard config commons */
 
/* String defs */
 
MenuHandle menus[MAX_MENU+1];           /* handle on our menus */
 
/* Global Variables */
 
int innum,                              /* Input driver refnum */
    outnum,                             /* Output driver refnum */
    protocmd;                           /* protocol file cmd, or -1 for */
                                        /*  remote cmds, or 0 if not in */
                                        /*  protocol */
 
char *mybuff;                           /* Serial drivers new buffer */
 
CursHandle watchcurs;                   /* the watch cursor */
 
WindowPtr theWindow;
WindowRecord wRecord;
 
/* Rectangles */
short wirect[]={40,5,335,505};          /* Kermit window in global */
CSParam controlparam;      /* To change serial driver paramaters */
 
int quit=FALSE;
 
struct QDVar QDVar;
 
/*
 *  p a r s e r
 *
 *  Entry point for kermit.
 *  Establish a virtual terminal connection with the remote host and
 *  process mouse events, such as selecting items from the menu bars.
 *
 */
 
char
parser()
{
    char domouse(),rstate = 0;
    EventRecord myevent;
    WindowPtr evtwindow;
    int evtwcode, evtwref;
 
    SetCursor(&QD->arrow);              /* back to normal cursor */
    protocmd = 0;                       /* protocol not active */
 
    while (quit == FALSE &&             /* Until they want to quit */
           rstate == 0)                 /* or return */
    {
        SystemTask();                   /* Update system things */
 
        inpchars();                     /* Handle all the pending port chars */
 
        flash_cursor(theWindow);        /* (UoR) for flashing cursor */
 
        check_pointer(theWindow);       /* (UoR) check for mouse cursor pointer
*/
 
        GetNextEvent(everyEvent,&myevent);
 
        switch (myevent.what)           /* events */
        {
            case keyDown:               /* Handle char input */
            case autoKey:               /*  both ways */
                if (FrontWindow() == theWindow) handle_char(&myevent);
                break;
 
            case updateEvt:             /* A window update event */
                doupdate((WindowPtr) myevent.message); /* Handle update */
                break;
 
            case activateEvt:           /* Something turning active */
                doactivate((WindowPtr) myevent.message,myevent.modifiers);
                break;
 
            case mouseDown:             /* Mouse event */
                evtwcode = FindWindow(&myevent.where,&evtwindow);
                if (evtwindow != (WindowPtr) NIL)
                    evtwref = GetWRefCon(evtwindow);
                rstate = domouse(evtwcode,evtwref,&myevent,evtwindow);
                break;
        }
    }
    if (quit)                           /* want to exit the program? */
     doexit(0);                         /* yes, finish up */
    SetCursor(*watchcurs);              /* set the watch */
    return(rstate);                     /* and return with state */
}
 
 
 
 
 
 
 
 
 
 
/* miniparser - called during protocol to handle events.  Handles dialog,
 *              update, and keydown (the abort key) events.  Ignores
 *              all other events.  The dialog events are assumed to
 *              be for screen (status) display.
 */
 
miniparser(deplete)                     /* deplete pending events */
{
  EventRecord ev;
  DialogPtr mydlg;
  int item;
 
  do {
    SystemTask();                       /* let the system move */
    GetNextEvent(everyEvent,&ev);       /* get an event */
 
    if (ev.what == nullEvent)
     return;                            /* depleted pending events */
 
    if (IsDialogEvent(&ev))             /* meant for dialog manager? */
     if (DialogSelect(&ev,&mydlg,&item))  /* must be for screen */
      scrmydlg(item);                   /* let him handle it */
 
    switch (ev.what) {                  /* we may need to do something */
      case updateEvt:
        doupdate((WindowPtr) ev.message); /* handle updates */
        break;
 
      case keyDown:
        if ((ev.modifiers & cmdKey) && ((ev.message & 0x7f) == '.'))
          if (CautionAlert(ALERT_ABORT,NILPROC) == OKBtn)
           sstate = 'a';                /* move into abort state */
        break;
    }
  } while (deplete);                    /* return now, or loop */
}
 
 
 
 
 
 
 
 
 
/* domouse  - handle mouse down events for different windows. */
 
char domouse(wcode,wref,evt,w)
int wcode, wref;
EventRecord *evt;
WindowPtr w;
{
    char menu_event(), state = 0;
    Rect dragrect;
 
    SetRect(&dragrect,4,24,508,338);
 
    switch (wcode)                      /* Tell us where */
    {
        case inMenuBar:                 /* Looking at the menus? */
            check_pointer((WindowPtr) NIL);     /* (UoR) mouse cursor off */
            state = menu_event(MenuSelect(&evt->where)); /* Yes... */
            HiliteMenu(0);              /* Done, so un-hilite */
            break;                      /* All done */
 
        case inSysWindow:               /* Looking at system, like */
            SystemClick(evt,w);         /* a desk accessary */
            break;                      /* Let the system handle it */
 
        case inContent:
            if (wref == RCD_WREF)
              rcdmouse(wcode,evt);
            else if (FrontWindow() == theWindow)
              mouse_cursor_move(evt);   /* (UoR) check for mouse cursor move */
            else
              SelectWindow(w);          /* make window current */
            break;
 
        case inDrag:                    /* Wanna drag? */
            if (wref == RCD_WREF)
              rcdmouse(wcode,evt);
            else
              DragWindow(w,&evt->where,&dragrect);
            break;
 
        case inGoAway:
        case inGrow:
            if (wref == RCD_WREF)       /* Our remote command window? */
                rcdmouse(wcode,evt);
            break;
   }
   flash_cursor((WindowPtr) NIL);       /* (UoR) reset timer for flashes */
   return(state);                       /* return with new state or 0 */
}
 
/* doupdate - handle update event on different windows, dispatch to
 *            redraw routines
 */
 
doupdate(w)
WindowPtr w;
{
    WindowPtr oldw;
 
    GetPort(&oldw);
 
    switch (GetWRefCon(w))
    {
        case SCR_WREF:                  /* The main screen window */
            BeginUpdate(w);
            SetPort(w);
            term_redraw();              /* Redraw terminal window */
            SetPort(oldw);
            EndUpdate(w);
            break;
 
        case RCD_WREF:                  /* Remote response window */
            BeginUpdate(w);
            SetPort(w);
            rcdupdate(w);               /* Draw it... */
            SetPort(oldw);
            EndUpdate(w);               /* All done */
            break;
 
        default:                        /* All others, do nothing */
            break;
    }
}
 
/* doactivate - activate a window */
 
doactivate(w,mod)
WindowPtr w;
int mod;
{
    switch (GetWRefCon(w))
    {
        case RCD_WREF:
            rcdactivate(mod);
            break;
    }
}
 
 
 
 
 
 
 
 
 
 
char genstr[100];
 
char menu_event(menu_item)
{
    int menu = HiWord(menu_item),       /* decompose arg */
        item = LoWord(menu_item);
    char state = '\0';
    int remotedialog();                 /* returns boolean */
 
    switch (menu)
    {
        case APPL_MENU:                 /* Mac system menu item */
            handapple(item);
            break;                      /* all done */
 
        case FILE_MENU:
            switch (item)               /* Find out which was selected */
            {
                case QUIT_FIL:          /* Want to quit program? */
                    quit = TRUE;        /* Yes... flag it */
                    break;
 
                case SAVE_FIL:          /* save settings */
                    savevals();         /* save em */
                    break;
 
                case LOAD_FIL:          /* load settings */
                    loadvals();
                    break;
 
                case SEND_FIL:          /* send a file: local, remote files */
                    if (!dosenddialog(&cmarg,&cmarg2))
                      break;
                    nfils = -1;         /* Use cmarg, not cmlist */
                    state = 's';        /* return with send state */
                    break;
 
                case RECV_FIL:          /* Ask for recv info -- */
                    initfilrecv();      /* init recv flags */
                    state = 'v';        /* return with recv state */
                    break;
 
                case GETS_FIL:          /* Get from server */
                    if (dogetfdialog(&cmarg))   /* remote-file. */
                      state = 'r';      /* Say we want to get */
                    break;
            }
            if (state != '\0')          /* going to enter protocol? */
            {
              protocmd = item;          /* yes, remember how */
              scrcreate();              /* create the status screen */
            }
            break;
 
        case SETG_MENU:
            switch (item)
            {
                case PROT_SETG:
                    protodialog();
                    break;
 
                case COMM_SETG:
                    commdialog();       /* communications dialog */
                    break;
 
                case FILE_SETG:
                    setfiledialog();    /* do default file settings */
                    break;
 
                case SCRD_SETG:         /* screen dump (CLOVER-SHIFT-1...) */
                    ScrDmpEnb = (ScrDmpEnb == scrdmpenabled) ?
                      scrdmpdisabled : scrdmpenabled; /* toggle */
                    CheckItem(menus[SETG_MENU],SCRD_SETG,
                               (ScrDmpEnb == scrdmpenabled));
                    break;
            }
            break;
 
/* return either 'g' for generic or 'c' for host with cmarg holding cmd */
 
        case REMO_MENU:
            cmarg = genstr;             /* indicate cmd ok to proceed */
            switch (item)
            {
                case RESP_REMO:         /* Want to toggle display */
                    togglercmdw();      /* Do it */
                    cmarg = NILPTR;     /* Don't do anything else */
                    break;
 
                case FIN_REMO:
                    setgen(genstr,'F',"","","");    /* Finish */
                    break;
 
                case BYE_REMO:
                    setgen(genstr,'L',"","","");  /* Bye, logout */
                    break;
 
                case SERV_REMO:
                    displa = 1;         /* umm */
                    scrcreate();        /* create the status screen */
                    protocmd = item;    /* ummm */
                    return('x');        /* ummm */
 
                default:
                    if (!remotedialog(item,genstr))
                        cmarg = NILPTR; /* cancel issued, prevent it */
                    break;
            }
            if (cmarg == NILPTR) break; /* Gave up on this command? */
            protocmd = -1;              /* hey we're going to protocol! */
            if (item == HOST_REMO)      /* Remote host? */
              state = 'c';              /* yes, return it to driver */
            else state = 'g';           /* else generic */
            break;
 
        case LAU_MENU:
            handlelaunch(item);         /* Handle x-fer to application */
            break;
    }
    return(state);                      /* Don't go into Kermit protocol */
}
 
 
 
 
 
 
 
 
 
/*
 * init_menus - create the menu bar.
 *
 */
 
setup_menus()
{
    int i;
 
    for (i=MIN_MENU; i<=MAX_MENU; i++)  /* For all menus */
    {
        menus[i] = GetMenu(i);          /* Fetch it from resource file */
        InsertMenu(menus[i],0);         /* Put it on menu line */
    }
    AddResMenu(menus[APPL_MENU],"DRVR");
    DrawMenuBar();                      /* Finish up by displaying the bar */
}
 
 
 
 
 
 
 
 
 
/*
 * mac_init - Initialize the macintosh and any window, menu, or other
 * resources we will be using.
 *
 */
 
mac_init()
{
    int err;
 
    QD = &QDVar;
 
    MaxApplZone();                      /* Make appl. heap big as can be */
    err = MoreMasters();                /* Create some more master pointers */
    if (err != noErr) printerr("Unable to create masters",err);
 
    InitGraf(&thePort);                 /* Init the graf port */
    InitFonts();                        /* The fonts */
    InitWindows();                      /* The windows */
    InitMenus();
    TEInit();                           /* Init text edit */
    InitDialogs(NILPROC);               /* The dialog manager */
    SetEventMask(everyEvent-keyUpMask);
 
    watchcurs = GetCursor(watchCursor); /* the waiting cursor */
 
    mybuff = NewPtr(MYBUFSIZE);         /* Allocate mybuff from the heap */
    if (mybuff == NIL) printerr("Unable to allocate mybuff",0);
 
    setup_menus();                      /* build our menus */
 
    ScrDmpEnb = scrdmpdisabled;         /* disable screen dumping */
 
    SetCursor(&QD->arrow);              /* start with a nice cursor */
 
    theWindow = NewWindow(&wRecord,(Rect *) wirect,"MacKermit",VIS,
        documentProc,(WindowPtr) -1,0,SCR_WREF); /* (UoR) noGoAway */
 
    initrcmdw();                        /* init remote cmd window */
    initfilset();                       /* init file settings */
 
    SetPort(theWindow);
    theWindow->txFont = 4;   /* Maco font with non-proportional spacing */
    theWindow->txSize = 9;
    PenSize(1,1);
 
    FlushEvents(everyEvent,0);          /* clear click ahead (ha!) */
 
    innum = OpenDriver(".AIn");         /* Set up IO drivers */
    outnum = OpenDriver(".AOut");
    setserial(innum,outnum,DSPEED,DEFPAR);  /* set speed parity */
 
    controlparam.serInBuff.serBPtr = mybuff; /* Make driver use larger buff */
    controlparam.serInBuff.serBLen = (short) MYBUFSIZE;
    err = Control(innum,9,&controlparam);
    if (err) printerr("Trouble making io buffer:",err);
 
    controlparam.serShk.fXOn = (char) FALSE;    /* Specify handshake options */
    controlparam.serShk.fCTS = (char) FALSE;
    controlparam.serShk.xOn = (char) 17;
    controlparam.serShk.xOff = (char) 19;
    controlparam.serShk.errs = (char) FALSE;
    controlparam.serShk.evts = (char) FALSE;
    controlparam.serShk.fInX = (char) FALSE;
    controlparam.serShk.null = (char) FALSE;
 
    err = Control(outnum,10,&controlparam);
    if (err) printerr("Trouble with handshake: ",err);
 
    consetup();                         /* Set up for connecting */
    displa = TRUE;                      /* Make everything goes to screen */
 
}
 
 
 
 
 
 
 
 
 
/*
 * mac_cleanup() - called before leaving this program to clean up any
 *                 dangling Mac stuff.  Called by doexit and transfer
 *
 */
 
mac_cleanup()
{
  ScrDmpEnb = scrdmpenabled;            /* re-enabled screen dumping */
}
 
/* doexit(status) - exit to shell.  Perhaps we should check for abnormal
 *                  status codes...
 */
 
doexit(status)
{
  mac_cleanup();                        /* make things tidy */
  ExitToShell();
}
 
conect()
{
    return;
}
 
cmdlin()
{
    return(0);                          /* Say that we parsed nothing */
}
 
chkint()
{
    return;
}
 
/* Only place we can initialize the mac stuff from */
 
cmdini()
{
    mac_init();                         /* Set up the Mac */
    findfinderfiles();                  /* see if file was selected */
}
 
#ifdef DEBUG
debug(flags,str,str2,num)
int flags, num;
char *str, *str2;
{
    char numbuf[10];
 
    if (!debflg) return;
 
    switch (flags)
    {
        default:
            NumToString(numbuf,num);
            ParamText(str,str2,numbuf,"");
            CautionAlert(ALERT_DEBUG,NILPROC);
            break;
    }
}
#endif
 
 
 
 
 
 
 
 
 
/* sleep - called during protocol for a dismiss.  Keep machine running
 *         with calls to the miniparser during this period.
 */
 
sleep(secs)
{
  PLONG finalticks;                     /* tickscount for exit */
 
  finalticks = TickCount()+(60*secs);   /* TickCount for exit  */
  while (finalticks > TickCount())      /* keep the machine running by */
  {
    miniparser(TRUE);                   /* deplete the Q */
    if (sstate == 'a')                  /* if in abort state, forget */
     return;                            /* this wait */
  }
}
 
ermsg(msg)                              /* Print error message */
char *msg;
{
    screen(SCR_EM,0,0l,msg);            /* Put the error on the screen */
    tlog(F110,"Error -",msg,0l);
}
 
intmsg(n)
long n;
{
    return;
}
 
#ifdef TLOG
tlog(f,s1,s2,n)
int f;
long n;
char *s1, *s2;
{
    return;
}
#endif
<<< ckmutl.c >>>
/* Edit by Frank on 20 Jun 5:25pm */
/* In commdialog(), don't set parity on sio chip. */
/* Edit by Bill on Apr 30 00:11 */
/* use mygetitem instead of getitem, it doesn't convert from pascal to c */
/* Redo handapple */
/* Edit by Bill on Apr 21 17:27 */
/* Try to fix meaning of TURN and TURNCH in dialog box */
/* Remove version from dofiledialog dialog box */
 
 
/*
 * file ckmutl.c
 *
 * Module of mackermit containing code for the menus and other MacIntosh
 * things.
 *
 */
 
/*
 Copyright (C) 1985, Trustees of Columbia University in the City of New York.
 Permission is granted to any individual or institution to use, copy, or
 redistribute this software so long as it is not sold for profit, provided this
 copyright notice is retained. 
*/
 
#include "ckcker.h"
#include "ckcdeb.h"
#include "ckmdef.h"			/* General Mac defs */
#include "ckmres.h"			/* Resource file defs */
#include <ctype.h>			/* For isdigit */
#include "mac/quickdraw.h"		/* Macintosh C interface */
#include "mac/osintf.h"
#include "mac/toolintf.h"
#include "mac/packintf.h"
 
extern MenuHandle menus[];
 

/*  B L D L E N  --  Make length-encoded copy of string  */
 
char *
bldlen(str,dest)
char *str, *dest;
{
    int len;
 
    len = strlen(str);
    *dest = tochar(len);
    strcpy(dest+1,str);
    return(dest+len+1);
}
 
/*  S E T G E N  --  Construct a generic command  */
 
setgen(stor,type,arg1,arg2,arg3)
char *stor, type, *arg1, *arg2, *arg3;
{
    char *upstr, *cp;
 
    cp = stor;
    *cp++ = type;
    *cp = '\0';
    if (*arg1 != '\0') {
	upstr = bldlen(arg1,cp);
	if (*arg2 != '\0') {
	    upstr = bldlen(arg2,upstr);
	    if (*arg3 != '\0') bldlen(arg3,upstr);
	}
    }
    debug(F110,"setgen",stor,0);
}

 
/*
 * printerr - display error message and number in standard error box.
 *
 */
 
printerr(str,err)
char *str;
int err; 
{
    int i;
    char error[10];
 
    if (err) 				/* Err=0 signals message only */
    {
	for(i=0; i<10; error[i++]='\0');    /* Make string null terminated */
 
	NumToString(err,error);  	/* Convert err number */
	ParamText(str,error,"",""); 	/* Insert strings into error box */
    }
    else ParamText(str,"","","");
 
    StopAlert(ALERT_ERROR,NILPROC);
}
 
 
/*
 * fatal - close file, and exit to shell.
 */
 
fatal(str,err)
char *str;
int err;
{
    printerr(str,err);
    doexit();				/* quit */
}

/* 
 * aboutKermit - Display the about kermit dialog box, wait for user to
 *     	      	 hit the OK button (maybe this should be a mouse click).
 *
 * The kermit version string is stored in the resource fork as type 
 * "KERM" ID 0 -- load this resource into memory, and lock it.  The
 * resource is locked so that we won't go off the deep end if the
 * heap gets compacted during the dialog display.  This would cause
 * problems because we are using the de-referenced handle, the actual
 * location of the string and not a pointer (handle) to it.
 *
 */
 
aboutKermit()
{
  Handle kversion;
  static char ktype[] = "KERM";
  DialogPtr kDialog;			/* our dialog */
  int itemhit;				/* item clicked */
 
  kversion = GetResource(ktype,0);	/* get version information */
  LoadResource(kversion);		/* make sure loaded */
  HLock(kversion);			/* prevent movement */
  ParamText(isapstr(*kversion),"","",""); /* set it up for display via ^0 */
					/*  de-reference the handle */
  kDialog = GetNewDialog(ABOUTID,NILPTR,(WindowPtr) -1);
  ModalDialog(NILPROC,&itemhit);	/* wait for OK */
  DisposDialog(kDialog);		/* dispose dialog box */
  HUnlock(kversion);			/* undo previous HLock */
  ReleaseResource(kversion);		/* no longer needed */
}
 

/* handapple - Handle the apple menu, either running a desk accessory
 *    	       or calling a routine to display information about our
 *    	       program.  For desk accessories use "mygetitem" instead
 *    	       of standard GetItem.  mygetitem does not convert the name
 *    	       into C form thus averting the problems of DA names with
 *    	       imbedded nulls (and those without).  Use the practice of
 *    	       checking for available memory, and saving the GrafPort
 *    	       described in the DA Manager's Guide.
 */
 
handapple(accitem)
int accitem;
{
    GrafPtr saveport;			/* Where to save current port */
    Handle acchdl;			/* holds ptr to accessory resource */
    char accname[255];			/* string holds accessory name */
    int accsize;			/* holds size of the acc + stack */
 
    if (accitem == 1)			/* tell about Kermit? */
    {
      aboutKermit();			/* yes, "about kermit" please */
      return;				/* and return */
    }
 
    mygetitem(menus[APPL_MENU],accitem,accname); /* get the pascal name */
    SetResLoad(FALSE);			/* don't load into memory */
    accsize = SizeResource(		/* figure out acc size + heap */
      	      	GetNamedResource('DRVR',isapstr(accname)+3072));
    acchdl = NewHandle(accsize);	/* try for a block this size */
    SetResLoad(TRUE);			/* reset flag for rsrc mgr */
    if (acchdl == NIL)			/* able to get a chunk? */
    {
      	printerr("Not enough memory for accessory. Requires: ",accsize);
	return;				/* failed */
    }
    DisposHandle(acchdl);		/* get rid of this handle */
    GetPort(&saveport);			/* save the current port */
    OpenDeskAcc(isapstr(accname));	/* run desk accessory */
    SetPort(saveport);			/* and put back our port */
}

/*
 * setserial - set the baud and parity for the serial port.
 *
 */
 
typedef struct {
  int kerval;
  int macval;
} KMTBL;
 
KMTBL kerbaudtbl[] = {
    {300,baud300},    {600,baud600},     {1200,baud1200},   {1800,baud1800},
    {2400,baud2400},  {4800,baud4800},   {7200,baud7200},   {9600,baud9600},
    {19200,baud19200},{57600,baud57600}
  };
 
#define kerbaudtblln ((sizeof (kerbaudtbl))/(sizeof (KMTBL)))
 
KMTBL kerparitytbl[] = {
    {KPARITY_ODD,MPARITY_ODD},    {KPARITY_EVEN,MPARITY_EVEN},
    {KPARITY_MARK,MPARITY_MARK},  {KPARITY_SPACE,MPARITY_SPACE},
    {KPARITY_NONE,MPARITY_NONE}
  };
 
#define kerparitytblln ((sizeof (kerparitytbl))/(sizeof (KMTBL)))
 
setserial(irefnum,orefnum,b,p)
{
  int err,i,mb,mp = 0;
 
  speed = b;				/* set global kermit value */
 
  for (i=0; i <= kerbaudtblln; i++)
    if (kerbaudtbl[i].kerval == b)
     mb = kerbaudtbl[i].macval;		/* set mac value for baud */
 
  for (i=0; i <= kerparitytblln; i++)
    if (kerparitytbl[i].kerval == p)
     mp = kerparitytbl[i].macval;	/* set mac value for parity */
     
  err = SerReset(irefnum,mb+mp);	/* reset serial input port */
  if (err != noErr)
   fatal("setserial couldn't set port: ",err);
   
  err = SerReset(orefnum,mb+mp);	/* reset serial output port */
  if (err != noErr)
   fatal("setserial couldn't set port: ",err);
}  
 

typedef struct {
  short resval;
  int serval;
 } RESSERTBL;
 
RESSERTBL commduplextbl[] = {		/* "echo" for duplex */
    {CRES_ECHOLCL,1},			/* local should do echo */
    {CRES_ECHOREM,0},			/* remote is doing echo */
    {0,0}};
 
RESSERTBL commbaudtbl[] = {
    {CRES_BAUD300,300},
    {CRES_BAUD600,600},
    {CRES_BAUD1200,1200},
    {CRES_BAUD1800,1800},
    {CRES_BAUD2400,2400},
    {CRES_BAUD4800,4800},
    {CRES_BAUD7200,7200},
    {CRES_BAUD9600,9600},
    {CRES_BAUD19200,19200},
    {CRES_BAUD57600,57600},
    {0,0}};
 
 
RESSERTBL commparitytbl[] = {
    {CRES_PARODD,KPARITY_ODD},
    {CRES_PAREVEN,KPARITY_EVEN},
    {CRES_PARMARK,KPARITY_MARK},
    {CRES_PARSPACE,KPARITY_SPACE},
    {CRES_PARNONE,KPARITY_NONE},
    {0,0}};
 
/*
 * rshilite - hilite the radio control item matching the given
 *    	  serial value, and disable all other control items in the
 *    	  resource-serial table.
 *
 */
 
rshilite(servalue,rstbl,dlg)
int servalue;
RESSERTBL rstbl[];
DialogPtr dlg;
{
 int i,itemtype;
 Rect itembox; 
 Handle itemhdl;
 
 for (i=0; rstbl[i].resval != 0; i++)
 {
   GetDItem(dlg,rstbl[i].resval,&itemtype,&itemhdl,&itembox);
   if (itemtype != ctrlItem + radCtrl)
    printerr("rshilite called with non radio control: ",rstbl[i].resval);
   if (rstbl[i].serval == servalue)
    SetCtlValue((ControlHandle) itemhdl,btnOn);
   else
    SetCtlValue((ControlHandle) itemhdl,btnOff);
 }
}
    
rsreference(rstbl,value,dlg)
RESSERTBL rstbl[];
DialogPtr dlg;
int value;
{
  int i,itemtype;
  Rect itembox;
  Handle itemhdl;
 
  for (i=0; rstbl[i].resval != 0; i++)
  {
   GetDItem(dlg,rstbl[i].resval,&itemtype,&itemhdl,&itembox);
   SetCRefCon((ControlHandle) itemhdl,value);
  }
}
 
/*
 * rsserval - given a resource ID for a control and a resource-serial
 *    	      table, return the serial value.
 */
 
int rsserval(resvalue,rstbl)
int resvalue;
RESSERTBL rstbl[];
{
 int i;
 for (i=0; rstbl[i].resval != 0; i++)
   if (rstbl[i].resval == resvalue)
    return(rstbl[i].serval);
 fatal("rsserval didn't find: ",resvalue);
 return(0);				/* never get here */
}
 
 
/*
 * commdialog - enter communications setup dialog.
 *
 */
 
#define CREF_BAUD 1
#define CREF_PARITY 2
#define CREF_ECHO 3
 
commdialog() 
{
  DialogPtr commdlg;
  int i,itemhit,itemtype,dlgspeed,dlgparity,dlgduplex;
  
  Handle itemhdl;
  Rect itembox;
 
  commdlg = GetNewDialog(COMMBOXID,NILPTR,(WindowPtr) -1);
  ShowWindow(commdlg);
 
  dlgspeed = speed;			/* initialize to current global */
  dlgparity = parity;			/*  values of baud and parity */
  dlgduplex = duplex;			/*  and tty emulator's duplex val */
 
  rshilite(dlgspeed,commbaudtbl,commdlg); /* hilite our baud */
  rshilite(dlgparity,commparitytbl,commdlg);	/* hilite our parity */
  rshilite(dlgduplex,commduplextbl,commdlg); /* hilite our echo mode */
  
/* for all baud and parity controls set the reference value for each
 * control to the resource-serial table address so we can manipulate
 * these controls easily during the dialog processing.
 */
 
  rsreference(commbaudtbl,CREF_BAUD,commdlg); /* setup control ref's */
  rsreference(commparitytbl,CREF_PARITY,commdlg);
  rsreference(commduplextbl,CREF_ECHO,commdlg);
 
  for (;;)
  {
    ModalDialog(NILPROC,&itemhit);
    switch (itemhit) {
      case OKBtn: 
	duplex = dlgduplex;		/* set for tty emulator */
	 				/* set fork kermit and mac */
	parity = dlgparity;
      	setserial(innum,outnum,dlgspeed,KPARITY_NONE);
 
      case QuitBtn:
      	DisposDialog(commdlg);	/* finished with the dialog */
	return;				/* so return */
	
      default:				/* default is radio button */
      	GetDItem(commdlg,itemhit,&itemtype,&itemhdl,&itembox);      
        i = GetCRefCon((ControlHandle) itemhdl);
	switch (i) {
	  case CREF_BAUD:
	    dlgspeed = rsserval(itemhit,commbaudtbl);
	    rshilite(dlgspeed,commbaudtbl,commdlg);
	    break;
	    
	  case CREF_PARITY:
	    dlgparity = rsserval(itemhit,commparitytbl);
	    rshilite(dlgparity,commparitytbl,commdlg);
	    break;			  
	    
      	  case CREF_ECHO:
	    dlgduplex = rsserval(itemhit,commduplextbl);
	    rshilite(dlgduplex,commduplextbl,commdlg);
	    break;
	    
          default:			  
	    printerr("Item has no refcon: ",itemhit);
	}
     }  
  }
}

RESSERTBL protoblktbl[] = {		/* block check:  */
  {PRES_BLK1,1},			/*  type 1 */
  {PRES_BLK2,2},			/*  type 2 */
  {PRES_BLK3,3},			/*  type 3 */
  {0,0}};
 
#define KTURN_NONE 0128			/* indicate no handshake */
 
RESSERTBL protohstbl[] = {		/* hand shake: */
  {PRES_HSBELL,7},			/*  bell = 7 */
  {PRES_HSCR,15},			/*  cr = 15 */
  {PRES_HSESC,33},			/*  esc = 33  */
  {PRES_HSLF,12},			/*  lf = 12 */
  {PRES_HSNONE,KTURN_NONE},		/*  none = 128 */
  {PRES_HSXON,XON},			/*  xon = 21 */
  {PRES_HSXOFF,23},			/*  xoff = 23 */
  {0,0}};
 
RESSERTBL protointtbl[] = {		/* edit text integer items: */
  {PRES_INPADN,0},			/* inbound pad count edit text */
  {PRES_OUTPADN,1},			/* outbound pad count edit text */
  {PRES_INTIMEO,2},			/* inbound secs timeout edit text */
  {PRES_OUTTIMEO,3},			/* outbound secs timeout edit text */
  {PRES_INPKTLEN,4},			/* inbound packet length edit text */
  {PRES_OUTPKTLEN,5},			/* outbound packet length edit text */
  {0,0}};
 
 
int *protointcells[] = {		/* parallel to above table! */
  &mypadn,				/* inbound pad count */
  &npad,				/* outbound pad count */
  &timint,				/* inbound timeout in secs */
  &rtimo,				/* outbound timeout in secs */
  &rpsiz,				/* inbound pkt length */
  &spsiz				/* inbound pkt length */
};
  
RESSERTBL protochrtbl[] = {		/* edit text character items: */
  {PRES_INPADC,0},			/* inbound pad chr edit text */  
  {PRES_OUTPADC,1},			/* outbound pad chr */
  {PRES_INEOP,2},			/* inbound end of packet edit text */
  {PRES_OUTEOP,3},			/* outbound end of packet edit text */
  {PRES_INSOP,4},			/* inbound start of pkt edit text */  
  {PRES_OUTSOP,5},			/* outbound start of pkt edit text */  
  {0,0}};
 
  
char *protochrcells[] = {		/* parallel to above table! */
  &mypadc,				/* inbound pad char */  
  &padch,				/* outbound pad char */
  &eol,					/* inbound end of packet char */
  &seol,				/* outbound end of pkt char */
  &stchr,				/* inbound start of pkt char */
  &mystch				/* outbound start of packet char */
};
 
 
/*
 * etsetval - Set the numeric value in the dialog's edit text item.
 *
 */
 
etsetval(item,val,dlg)
DialogPtr dlg;
int item,val;
{
 int itemtype;
 Rect itemrect;
 Handle itemhdl;
 char itembuf[10];
 
 NumToString(val,itembuf); 
 GetDItem(dlg,item,&itemtype,&itemhdl,&itemrect);
 if (itemtype != editText)
  printerr("Bad item in etsetvalue: ",item);
 else
  SetIText(itemhdl,itembuf);
}
 
/*
 * etgetcc - Set edit text paramter from dialog window to an ASCII
 *    	     control character value.  Returns FALSE if value is
 *    	     illegal, warning has been displayed.
 */
 
int etgetcc(item,dlg,chrcell)
DialogPtr dlg;
int item;
char *chrcell;
{
 int itemtype,i;
 int rslt;
 Rect itemrect;
 Handle itemhdl;
 char itembuf[256],c;
 
 GetDItem(dlg,item,&itemtype,&itemhdl,&itemrect);
 if (itemtype != editText)
 {
  printerr("etsetcc item not editText: ",item);
  return(FALSE);
 }
 GetIText(itemhdl,itembuf);
/* p2cstr(itembuf);			/* convert to c string */
 for (i=0; (c = itembuf[i]) != 0; i++)	/* check for digits */
  if (!isdigit(c))
  {
    printerr("Field contains a non numeric, code ",c);
    return(FALSE);
  }
 StringToNum(itembuf,&rslt);
 if ((rslt > 037) && (rslt != 0177))
 {
  printerr("Not in ASCII control range: ",rslt);
  return(FALSE);
 }
 *chrcell = (char) rslt;
 return(TRUE);
}
 
/*
 * etgetnum - Set edit text paramet from dialog to numeric cell.
 *    	      Returns FALSE if value is non numeric or not in range
 *    	      in which case an error message is printed.
 */
 
int etgetnum(item,dlg,intcell)
DialogPtr dlg;
int item;
int *intcell;
{
 int itemtype,i;
 int rslt;
 Rect itemrect;
 Handle itemhdl;
 char itembuf[256],c;
 
 GetDItem(dlg,item,&itemtype,&itemhdl,&itemrect);
 if (itemtype != editText)
 {
  printerr("etsetnum item not editText: ",item);
  return(FALSE);
 }
 GetIText(itemhdl,itembuf);
/* p2cstr(itembuf);			/* convert to c string */
 for (i=0; (c = itembuf[i]) != 0; i++)	/* check for digits */
  if (!isdigit(c))
  {
    printerr("Field contains a non numeric, code ",c);
    return(FALSE);
  }
 StringToNum(itembuf,&rslt);
 if (rslt > 94)
 {
  printerr("Sorry, 94 is the maximum: ",rslt);
  return(FALSE);
 }
 *intcell = (int) rslt;
 return(TRUE);
}
 
 
/*
 * protodialog - enter protocol setup dialog.
 *
 */
 
#define PREF_BLKCHK 1
#define PREF_HNDSHK 2
 
protodialog() {
  
  DialogPtr protoDialog;
  int i,itemhit,itemtype,dlgval,dlgint,dlgbctr,dlgturnch;
  Handle itemhdl;
  Rect itembox;
  char dlgchr;
 
  protoDialog = GetNewDialog(PROTOBOXID,NILPTR,(WindowPtr) -1);
  ShowWindow(protoDialog);
 
  dlgbctr = bctr;			/* init local block check */
  dlgturnch = turnch;			/* handshake */
  if (!turn)				/* no turn character? */
   dlgturnch = KTURN_NONE;		/* indicate none */
 
/* for all button controls set the reference value */
 
  rsreference(protohstbl,PREF_HNDSHK,protoDialog);
  rsreference(protoblktbl,PREF_BLKCHK,protoDialog);
 
/* for each button controls, hilite the current setting */
 
  rshilite(dlgturnch,protohstbl,protoDialog); /* hilite our hand shake */
  rshilite(dlgbctr,protoblktbl,protoDialog);  /* hilite our block check */
 
/* for each edit text item, set current value in edit text */
  
  for (i=0; protochrtbl[i].resval != 0; i++)
    etsetval(protochrtbl[i].resval,
      	      (int) *protochrcells[i],protoDialog);
	      
  for (i=0; protointtbl[i].resval != 0; i++)
    etsetval(protointtbl[i].resval,
      	       *protointcells[i],protoDialog);
 
  for (;;) {
 
    ModalDialog(NILPROC,&itemhit);
    
    switch (itemhit) {
      case OKBtn:			/* finish up */
 
      	turnch = dlgturnch;		/* set global handshake */
	turn = (turnch == KTURN_NONE) ? FALSE : TRUE;	/* set turn */
	bctr = dlgbctr;			/* set block type check */
	
	for (i=0; protochrtbl[i].resval != 0; i++)  /* set chr vals */
          if (!etgetcc(protochrtbl[i].resval,protoDialog,protochrcells[i]))
            fatal("During OKBtn etgetcc failed!",i);     
 
	for (i=0; protointtbl[i].resval != 0; i++)  /* set int vals */
	  if (!etgetnum(protointtbl[i].resval,protoDialog,protointcells[i]))
          fatal("During OKBtn etgetnum failed!",i);
	  
      case QuitBtn:			/* fall in from above */
      	DisposDialog(protoDialog);	/* finished with the dialog */
	return;				/* return */
 
      case PRES_INPADC:
      case PRES_OUTPADC:
      case PRES_INEOP:
      case PRES_OUTEOP:
      case PRES_INSOP:
      case PRES_OUTSOP:
      	if (!etgetcc(itemhit,protoDialog,&dlgchr))
	{
	  dlgval = rsserval(itemhit,protochrtbl); /* get back tbl idx */
	  dlgval = (int) *protochrcells[dlgval];  /* now cell value */
	  etsetval(itemhit,dlgval,protoDialog);   /* and reset it */
      	}
	break;
 
      case PRES_INPADN:
      case PRES_OUTPADN:
      case PRES_INTIMEO:
      case PRES_OUTTIMEO:
      case PRES_INPKTLEN:
      case PRES_OUTPKTLEN:
      	if (!etgetnum(itemhit,protoDialog,&dlgint))	  
	{
	  dlgval = rsserval(itemhit,protointtbl); /* get back tbl idx */
	  dlgval = *protointcells[dlgval]; /* now cell value */
	  etsetval(itemhit,dlgval,protoDialog); /* and reset it */
      	}
	break;
 
      default:
      	GetDItem(protoDialog,itemhit,&itemtype,&itemhdl,&itembox);          
	if (itemtype != ctrlItem+radCtrl)	/* must be radio button */
	 fatal("Not radio button",itemhit);
	i = GetCRefCon((ControlHandle) itemhdl);
	if (i == PREF_BLKCHK)
	{
	  dlgbctr = rsserval(itemhit,protoblktbl);
	  rshilite(dlgbctr,protoblktbl,protoDialog);
      	}
	else if (i == PREF_HNDSHK)
	{
	  dlgturnch = rsserval(itemhit,protohstbl);
	  rshilite(dlgturnch,protohstbl,protoDialog);
      	}
	else printerr("raido item has bad refcon: ",itemhit);
	break;				/* all done with radio buttons */
      }
   }
}
  
    
/*
 * handlelaunch - Handle transfer to another application.  Called when
 *    	  "launch" selected from menu bar.
 *
 */
 
struct launchparams {
	char	*lnamep;
	long	lunknown;
	short	lsound;
  } lparams;
char lfile[32];
 
handlelaunch(item)
{
 SFReply sfr;
 static char appltype[] = "APPL";	/* wan't to be long aligned */
 Point where;
 
 if (item == TOAP_LAU)			/* they want to select application */
 {
  SetPt(&where,75,115);
  SFGetFile(&where,"",NILPROC,1,appltype,NILPROC,&sfr);
  if (!sfr.good)			/* hit cancel, return now */
   return;
   
  mac_cleanup();			/* about to leave, leave clean! */
   
  p2cstr(sfr.fName);
  strcpy(lfile,sfr.fName);
  c2pstr(lfile);
  }
  lparams.lnamep = lfile;  
  lparams.lunknown = 0;
  lparams.lsound = 0;
  SetVol((char *)0,sfr.vRefNum);	/* allow any drive */
  asm("lea lparams,a0");
  asm(".word 0xa9f2");
}
