Date: Thu, 07 Mar 1991 14:39:06 EST
From: Earle Ake - SAIC <ake@Dayton.SAIC.COM>
To: madison@vms.ecs.rpi.edu
Message-ID: <00945412.9d3f6860.6128@Dayton.SAIC.COM>
Subject: name_conversion and changes to command procedures for it

Matt,

	Here is the code for the name_conversion to handle DECnet mail into
MX and the mods I made to the MX_START and MX_STARTUP command procedures.
I think I have the logical defined and the image installed before I start
the router.  Let me know what you think.  I may have over commented the
code but it took me awhile to figure it out.  My 'C' knowledge is limited
as I know it but don't normally program in it.  Maybe I will get motivated
and write a similar piece in FORTRAN.  Let me know what you think.


Earle
_____________________________________________________________________________
             ____ ____    ___
Earle Ake   /___ /___/ / /     Science Applications International Corporation
           ____//   / / /__                 Dayton, Ohio
-----------------------------------------------------------------------------
Internet: ake@dayton.saic.com        uucp: dayvb!ake         SPAN: 28284::ake


$! ------------------ CUT HERE -----------------------
$ v='f$verify(f$trnlnm("SHARE_VERIFY"))'
$!
$! This archive created by VMS_SHARE Version 7.2-007  22-FEB-1990
$!   On  7-MAR-1991 14:34:49.12   By user AKE (Earle Ake - SAIC (513) 429-6500)
$!
$! This VMS_SHARE Written by:
$!    Andy Harper, Kings College London UK
$!
$! Acknowledgements to:
$!    James Gray       - Original VMS_SHARE
$!    Michael Bednarek - Original Concept and implementation
$!
$! TO UNPACK THIS SHARE FILE, CONCATENATE ALL PARTS IN ORDER
$! AND EXECUTE AS A COMMAND PROCEDURE  (  @name  )
$!
$! THE FOLLOWING FILE(S) WILL BE CREATED AFTER UNPACKING:
$!       1. NAME_CONVERSION.C;117
$!       2. MX_START.DIFF;1
$!       3. MX_STARTUP.DIFF;1
$!
$set="set"
$set symbol/scope=(nolocal,noglobal)
$f=f$parse("SHARE_TEMP","SYS$SCRATCH:.TMP_"+f$getjpi("","PID"))
$e="write sys$error  ""%UNPACK"", "
$w="write sys$output ""%UNPACK"", "
$ if f$trnlnm("SHARE_LOG") then $ w = "!"
$ ve=f$getsyi("version")
$ if ve-f$extract(0,1,ve) .ges. "4.4" then $ goto START
$ e "-E-OLDVER, Must run at least VMS 4.4"
$ v=f$verify(v)
$ exit 44
$UNPACK: SUBROUTINE ! P1=filename, P2=checksum
$ if f$search(P1) .eqs. "" then $ goto file_absent
$ e "-W-EXISTS, File ''P1' exists. Skipped."
$ delete 'f'*
$ exit
$file_absent:
$ if f$parse(P1) .nes. "" then $ goto dirok
$ dn=f$parse(P1,,,"DIRECTORY")
$ w "-I-CREDIR, Creating directory ''dn'."
$ create/dir 'dn'
$ if $status then $ goto dirok
$ e "-E-CREDIRFAIL, Unable to create ''dn'. File skipped."
$ delete 'f'*
$ exit
$dirok:
$ w "-I-PROCESS, Processing file ''P1'."
$ if .not. f$verify() then $ define/user sys$output nl:
$ EDIT/TPU/NOSEC/NODIS/COM=SYS$INPUT 'f'/OUT='P1'
PROCEDURE Unpacker ON_ERROR ENDON_ERROR;SET(FACILITY_NAME,"UNPACK");SET(
SUCCESS,OFF);SET(INFORMATIONAL,OFF);f:=GET_INFO(COMMAND_LINE,"file_name");b:=
CREATE_BUFFER(f,f);p:=SPAN(" ")@r&LINE_END;POSITION(BEGINNING_OF(b));
LOOP EXITIF SEARCH(p,FORWARD)=0;POSITION(r);ERASE(r);ENDLOOP;POSITION(
BEGINNING_OF(b));g:=0;LOOP EXITIF MARK(NONE)=END_OF(b);x:=ERASE_CHARACTER(1);
IF g=0 THEN IF x="X" THEN MOVE_VERTICAL(1);ENDIF;IF x="V" THEN APPEND_LINE;
MOVE_HORIZONTAL(-CURRENT_OFFSET);MOVE_VERTICAL(1);ENDIF;IF x="+" THEN g:=1;
ERASE_LINE;ENDIF;ELSE IF x="-" THEN IF INDEX(CURRENT_LINE,"+-+-+-+-+-+-+-+")=
1 THEN g:=0;ENDIF;ENDIF;ERASE_LINE;ENDIF;ENDLOOP;t:="0123456789ABCDEF";
POSITION(BEGINNING_OF(b));LOOP r:=SEARCH("`",FORWARD);EXITIF r=0;POSITION(r);
ERASE(r);x1:=INDEX(t,ERASE_CHARACTER(1))-1;x2:=INDEX(t,ERASE_CHARACTER(1))-1;
COPY_TEXT(ASCII(16*x1+x2));ENDLOOP;WRITE_FILE(b,GET_INFO(COMMAND_LINE,
"output_file"));ENDPROCEDURE;Unpacker;QUIT;
$ delete/nolog 'f'*
$ CHECKSUM 'P1'
$ IF CHECKSUM$CHECKSUM .eqs. P2 THEN $ EXIT
$ e "-E-CHKSMFAIL, Checksum of ''P1' failed."
$ ENDSUBROUTINE
$START:
$ create 'f'
X/*
X!++
X!
X! MODULE:   `09    NAME_CONVERSION
X!
X! FACILITY: `09    MX examples
X!
X! ABSTRACT: `09    Example of site-installable nickname conversion.
X!
X! MODULE DESCRIPTION:
X!
X!   This module contains routines for use by MX modules (specifically,
X!   the MX_MAILSHR interface to VMS Mail and the MX_ROUTER agent process)
X!   for translating between actual VMS usernames and site-specific aliases.
X!
X!   This module contains a fairly primitive lookup table to implement
X!   the translation.
X!
X!   To use this module: MODIFY IT AS NEEDED FOR YOUR SITE, then compile it
X!   and link it with the commands:
X!
X!       $ cc name_conversion
X!   `09$ link/share/notrace name_conversion,sys$input:/opt
X!   `09    sys$share:vaxcrtl/share
X!   `09    universal=init,convert,cleanup
X!   `09    <ctrl/Z>
X!
X!   Then copy it to MX_EXE and make it available with the commands:
X!
X!   `09$ copy name_conversion.exe mx_exe:/protection=w:re
X!   `09$ install create mx_exe:name_conversion/share/open/header
X!   `09$ define/system/exec mx_site_name_conversion mx_exe:name_conversion
X!   `09$ mcp reset router  ! to force Router to load the code
X!
X!   (You need a suitably privileged account to do this.)
X!
X! AUTHOR:   `09    M. Madison
X!   `09    `09    COPYRIGHT `A9 1990, RENSSELAER POLYTECHNIC INSTITUTE.
X!
X!   THIS SOFTWARE IS PROVIDE "AS IS".  NEITHER THE AUTHOR NOR RENSSELAER
X!   MAKE ANY GUARANTEES REGARDING THE SUITABILITY, RELIABILITY, SECURITY,
X!   USEFULNESS, OR PERFORMANCE OF THIS SOFTWARE.  >>USE AT YOUR OWN RISK.
X!
X! CREATION DATE:    03-DEC-1990
X!
X! MODIFICATION HISTORY:
X!
X!   03-DEC-1990`09V1.0`09Madison`09    Initial coding.
X!
X!   07-MAR-1991 V1.1`09Ake         Added support for non-MX nodes mailing
X!`09`09`09`09    into MX generating a decent return address
X!--
X*/
X
X#include descrip
X#include string
X#include stdio
X#include ssdef
X#include str$routines
X#include lib$routines
X
X#define NICK_TO_ADDRESS`09    1
X#define USERNAME_TO_NICK    2
X
X#define NAME_COUNT  `09    0
X
Xstatic char *user `5B`5D = `7B"MADISON", "SYSTEM"`7D;
Xstatic char *nick `5B`5D = `7B"M.Madison", "System.Manager"`7D;
Xstatic char *dcolon `5B`5D = `7B"::"`7D;
X
Xstruct context `7B
X    struct dsc$descriptor localnode;
X    `7D;
X   `20
X
X/*
X!++
X!
X! ROUTINE NAME:`09    INIT
X!
X! FUNCTIONAL DESCRIPTION:
X!
X!   Allocates and initializes context block for subsequent name conversions.
X!
X! RETURNS:  `09cond_value, longword (unsigned), write only, by value
X!
X! PROTOTYPE:
X!
X!   INIT  ctxptr
X!
X! ctxptr:   pointer, longword (unsigned), modify, by reference
X!
X! IMPLICIT INPUTS:  None.
X!
X! IMPLICIT OUTPUTS: None.
X!
X! COMPLETION CODES:
X!
X!   SS$_NORMAL:`09    `09normal successful completion.
X!
X! SIDE EFFECTS:
X!
X!   None.
X!--
X*/
Xunsigned int
Xinit (struct context **ctx) `7B
X
X    int ctxsize;
X    $DESCRIPTOR(mx_node_name,"MX_NODE_NAME");
X
X    ctxsize = sizeof(struct context);
X    lib$get_vm (&ctxsize, ctx);
X    (*ctx)->localnode.dsc$b_dtype = DSC$K_DTYPE_T;
X    (*ctx)->localnode.dsc$b_class = DSC$K_CLASS_D;
X    (*ctx)->localnode.dsc$w_length = 0;
X    (*ctx)->localnode.dsc$a_pointer = NULL;
X    lib$sys_trnlog (&mx_node_name, 0, &(*ctx)->localnode);
X    return SS$_NORMAL;
X`7D  /* init */
X
X/*
X!++
X!
X! ROUTINE NAME:`09    CONVERT
X!
X! FUNCTIONAL DESCRIPTION:
X!
X!   Converts username -> nickname or nickname -> RFC821-address.
X!
X!   NB: You MUST use STR$ routines to copy result to OUTSTR parameter
X!       to ensure proper operation!!!!
X!
X!       You _may_ safely assume that INSTR is compatible with a DTYPE_T,
X!   `09CLASS_S (standard fixed-length) string descriptor.
X!
X! RETURNS:  `09cond_value, longword (unsigned), write only, by value
X!
X! PROTOTYPE:
X!
X!   CONVERT  ctxptr, code, instr, outstr
X!
X! ctxptr:   pointer, longword (unsigned), modify, by reference
X! code:`09    longword_unsigned, longword (unsigned), read only, by referenc
Ve
X! instr:    char_string, character string, read only, by descriptor (fixed)
X! outstr:   char_string, character string, write only, by descriptor
X!
X! IMPLICIT INPUTS:  None.
X!
X! IMPLICIT OUTPUTS: None.
X!
X! COMPLETION CODES:
X!
X!   SS$_NORMAL:`09    `09normal successful completion.
X!
X! SIDE EFFECTS:
X!
X!   None.
X!--
X*/
Xunsigned int
Xconvert (struct context **ctx, int *code, struct dsc$descriptor *instr,
X    `09    struct dsc$descriptor *outstr) `7B
X
X    struct dsc$descriptor tmp, tmp2, tmp3;
X    size_t count;
X    int i, j, retstat;
X    $DESCRIPTOR(lbrack, "<");
X    $DESCRIPTOR(rbrack, ">");
X    $DESCRIPTOR(atsign, "@");
X    $DESCRIPTOR(percent, "%");
X    $DESCRIPTOR(dnet, ".dnet");
X
X    char *user_name`5B256`5D, *node_name`5B256`5D;
X    int user_name_len, node_name_len;
X
X    count = instr -> dsc$w_length;
X    tmp.dsc$b_dtype = DSC$K_DTYPE_T;
X    tmp.dsc$b_class = DSC$K_CLASS_D;
X    tmp.dsc$w_length = 0;
X    tmp.dsc$a_pointer = NULL;
X
X    tmp2.dsc$b_dtype = DSC$K_DTYPE_T;
X    tmp2.dsc$b_class = DSC$K_CLASS_S;
X
X    switch (*code) `7B
X/*
X!++
X!  Local alias -> address
X!
X!   This code should return a status of SS$_NORMAL if an alias is found,
X!   0 otherwise.
X!
X!   If an alias is found, the resulting string MUST BE IN RFC821 format:
X!
X!   `09    `09    `09    `09<user@host>
X!
X!   >>>>>> EVEN IF THE ADDRESS IS FOR THE LOCAL HOST (so you have to
X!   look up MX_NODE_NAME and tack it on after the translated name,
X!   if you're just doing a local-host user directory).
X!--
X*/
X    `09case NICK_TO_ADDRESS:
X    `09    retstat = 0;
X    `09    str$copy_dx(&tmp, instr);
X    `09    for (i = 0; i < NAME_COUNT; i++) `7B
X    `09    `09tmp2.dsc$w_length = strlen(nick`5Bi`5D);
X    `09    `09tmp2.dsc$a_pointer = nick`5Bi`5D;
X    `09    `09if (str$case_blind_compare(instr, &tmp2) == 0) `7B
X    `09    `09    j = strlen(user`5Bi`5D);
X    `09    `09    str$copy_r(&tmp, &j, user`5Bi`5D);
X    `09    `09    str$concat(outstr, &lbrack, &tmp, &atsign,
X    `09    `09    `09&(*ctx)->localnode, &rbrack);
X    `09    `09    retstat = SS$_NORMAL;
X    `09    `09    break;
X    `09    `09`7D
X    `09    `7D
X    `09    break;
X
X/*
X!++
X!   Username -> Alias
X!
X!   EVEN IF THE USERNAME HAS NO ALIAS, you MUST provide a translation
X!   string (so just copy instr to outstr)!!!!!
X!
X!   Added the function to translate incoming DECnet mail return addresses
X!   through MX to look like user%decnetnode.dnet@domain-name instead of the
X!   current 'decnetnode::user'@domain-name format.  Remember to add mail
X!   rewrite rules to handle the new format.
X!
X!   Earle F. Ake     7 March 1991
X!   Science Applications International Corporation
X!   e-mail: ake@dayton.saic.com
X!
X!--
X*/
X    `09case USERNAME_TO_NICK:
X    `09    str$copy_dx(&tmp, instr);
X`09    *user_name = tmp.dsc$a_pointer;
X
X/*
X!++
X!   Put the initial pointer given into the tmp3 structure
X!   This is the starting point for our conversion
X!
X!--
X*/
X`09    tmp3.dsc$b_dtype = DSC$K_DTYPE_T;
X`09    tmp3.dsc$b_class = DSC$K_CLASS_D;
X`09    tmp3.dsc$w_length = tmp.dsc$w_length;
X`09    tmp3.dsc$a_pointer = tmp.dsc$a_pointer;
X
X/*
X!++
X!   Point the existing structure tmp2 at a string containing "::"
X!
X!--
X*/
X`09    tmp2.dsc$w_length = strlen(dcolon`5B0`5D);
X`09    tmp2.dsc$a_pointer = dcolon`5B0`5D;
X
X/*
X!++
X!   Look for the "::" in the given string
X!
X!--
X*/
X`09    j = str$position(&tmp3, &tmp2);
X`09    if ( j != 0) `7B
X
X/*
X!++
X!   If one is located we need to reduce the from address of the form
X!
X!        node1::node2::node3...noden::user
X!
X!            to
X!
X!        noden::user
X!
X!   The nodes node1, node2, etc are just routing nodes and
X!   don't need to be saved.  One should be able to reply to the message
X!   given just noden::user
X!
X!--
X*/
X`09`09do `7B
X`09`09    *node_name = *user_name;`09`09`09/* node points at user location *
V/
X`09`09    node_name_len = j - 1;`09`09`09/* node length is position of "::"
V minus 1 */
X`09`09    *user_name = *node_name + j + 1;`09`09/* new user is two past posi
Vtion of "::" */
X`09`09    tmp3.dsc$w_length = tmp.dsc$w_length -`09/* user length is origina
Vl length minus quantity */
X`09`09`09(*user_name - tmp.dsc$a_pointer);`09    /* user ptr minus original
V ptr */
X`09    `09    tmp3.dsc$a_pointer = *user_name;`09`09/* new tmp3 points at ne
Vw user ptr */
X`09`09    j = str$position(&tmp3, &tmp2);`09`09/* search remaining string fo
Vr another "::" */
X`09`09`7D while (j != 0);`09`09`09`09/* anymore "::" found in the remaining
V string? */
X
X/*
X!++
X!   What we have now is tmp3 pointing at the
X!   valid username and it's length
X!
X!--
X*/
X`09`09str$concat(outstr, &tmp3, &percent);`09`09/* Make the user% piece */
X`09`09tmp3.dsc$a_pointer = *node_name;`09`09/* point tmp3 at node */
X`09`09tmp3.dsc$w_length = node_name_len;`09`09/* set node length */
X`09`09str$concat(outstr, outstr, &tmp3, &dnet);`09/* now add the node.dnet t
Vo the */
X`09`09`09`09`09`09`09`09/* user% piece */
X
X/*
X!++
X!   We now have converted the node1::node2::user string to
X!   user%node2.dnet string which will be later appended to
X!   the domain-name string giving a return address of
X!
X!   user%node2.dnet@domain-name
X!
X!   Conversion is complete, set return code and leave
X!
X!--
X*/
X`09`09retstat = SS$_NORMAL;
X`09`09break;
X`09    `7D else `7B
X`09`09for (i = 0; i < NAME_COUNT; i++) `7B
X    `09    `09    tmp2.dsc$w_length = strlen(user`5Bi`5D);
X    `09    `09    tmp2.dsc$a_pointer = user`5Bi`5D;
X    `09    `09    if (str$case_blind_compare(instr, &tmp2) == 0) `7B
X    `09    `09        j = strlen(nick`5Bi`5D);
X    `09    `09        str$copy_r(&tmp, &j, nick`5Bi`5D);
X    `09    `09        break;
X`09`09    `7D
X`09`09`7D
X`09`09str$copy_dx(outstr, &tmp);
X`09`09retstat = SS$_NORMAL;
X`09`09break;
X`09    `7D
X    `7D
X    str$free1_dx(&tmp);
X    return retstat;
X`7D  /* convert */
X
X/*
X!++
X!
X! ROUTINE NAME:`09    CLEANUP
X!
X! FUNCTIONAL DESCRIPTION:
X!
X!   Deallocates context block allocated by init routine.
X!
X! RETURNS:  `09cond_value, longword (unsigned), write only, by value
X!
X! PROTOTYPE:
X!
X!   CLEANUP  ctxptr
X!
X! ctxptr:   pointer, longword (unsigned), modify, by reference
X!
X! IMPLICIT INPUTS:  None.
X!
X! IMPLICIT OUTPUTS: None.
X!
X! COMPLETION CODES:
X!
X!   SS$_NORMAL:`09    `09normal successful completion.
X!
X! SIDE EFFECTS:
X!
X!   None.
X!--
X*/
Xunsigned int
Xcleanup (struct context **ctx) `7B
X
X    int ctxsize;
X
X    str$free1_dx(&(*ctx)->localnode);
X    ctxsize = sizeof(struct context);
X    lib$free_vm (&ctxsize, ctx);
X    *ctx = NULL;
X    return SS$_NORMAL;
X`7D  /* cleanup */
$ CALL UNPACK NAME_CONVERSION.C;117 992077441
$ create 'f'
X************
XFile MX_ROOT:`5BEXE`5DMX_START.COM;24
X  128   $ IF F$TRNLNM ("MX_SITE_NAME_CONVERSION") .NES. ""
X  129   $ THEN
X  130   $   icmd := create
X  131   $   IF F$FILE_ATTR ("MX_SITE_NAME_CONVERSION:.EXE","KNOWN") THEN icm
Vd := replace
X  132   $   INSTALL 'icmd' MX_SITE_NAME_CONVERSION
X  133   $ ENDIF
X  134   $ icmd := create
X******
XFile MX_ROOT:`5BEXE`5DMX_START.COM;23
X  128   $ icmd := create
X************
X
XNumber of difference sections found: 1
XNumber of difference records found: 6
X
XDIFFERENCES /IGNORE=()/MERGED=1/OUTPUT=MX_ROOT:`5BEXAMPLES`5DMX_START.DIFF;1
V-
X    MX_ROOT:`5BEXE`5DMX_START.COM;24-
X    MX_ROOT:`5BEXE`5DMX_START.COM;23
$ CALL UNPACK MX_START.DIFF;1 755374048
$ create 'f'
X************
XFile SYS$COMMON:`5BSYS$STARTUP`5DMX_STARTUP.COM;90
X   28   $ DEFINE/SYSTEM/EXEC MX_SITE_NAME_CONVERSION MX_EXE:NAME_CONVERSION
X   29   $!
X******
XFile SYS$COMMON:`5BSYS$STARTUP`5DMX_STARTUP.COM;89
X   28   $!
X************
X
XNumber of difference sections found: 1
XNumber of difference records found: 1
X
XDIFFERENCES /IGNORE=()/MERGED=1/OUTPUT=MX_ROOT:`5BEXAMPLES`5DMX_STARTUP.DIFF
V;1-
X    SYS$COMMON:`5BSYS$STARTUP`5DMX_STARTUP.COM;90-
X    SYS$COMMON:`5BSYS$STARTUP`5DMX_STARTUP.COM;89
$ CALL UNPACK MX_STARTUP.DIFF;1 744826234
$ v=f$verify(v)
$ EXIT
--------------------------------------------------------------------------------
Return-Path: <@mdmvs.ecs.rpi.edu,@vms.ecs.rpi.edu:ake@Dayton.SAIC.COM>
Received: from vms.ecs.rpi.edu by mdmvs.ecs.rpi.edu (MX V2.2-1) with SMTP; Thu,
          07 Mar 1991 14:41:59 EST
Received: from dayva.dayton.saic.com by vms.ecs.rpi.edu (MX V2.2-1) with SMTP;
          Thu, 07 Mar 1991 14:39:09 EST
Received: by Dayton.SAIC.COM (MX V2.2-1) id 6128; Thu, 07 Mar 1991 14:39:06 EST
