/* !++ ! ! MODULE: NAME_CONVERSION ! ! FACILITY: MX examples ! ! ABSTRACT: Example of site-installable nickname conversion. ! ! MODULE DESCRIPTION: ! ! This module contains routines for use by MX modules (specifically, ! the MX_MAILSHR interface to VMS Mail and the MX_ROUTER agent process) ! for translating between actual VMS usernames and site-specific aliases. ! ! This module contains a fairly primitive lookup table to implement ! the translation. ! ! To use this module: MODIFY IT AS NEEDED FOR YOUR SITE, then compile it ! and link it with the commands: ! ! $ cc name_conversion ! $ link/share/notrace name_conversion,sys$input:/opt ! sys$share:vaxcrtl/share ! universal=init,convert,full_convert,cleanup ! ! ! Then copy it to MX_EXE and make it available with the commands: ! ! $ copy name_conversion.exe mx_exe:/protection=w:re ! $ install create mx_exe:name_conversion/share/open/header ! $ define/system/exec mx_site_name_conversion mx_exe:name_conversion ! $ mcp reset router ! to force Router to load the code ! ! (You need a suitably privileged account to do this.) ! ! AUTHOR: M. Madison ! ! Copyright (c) 2008, Matthew Madison. ! ! All rights reserved. ! ! Redistribution and use in source and binary forms, with or without ! modification, are permitted provided that the following conditions ! are met: ! ! * Redistributions of source code must retain the above ! copyright notice, this list of conditions and the following ! disclaimer. ! * Redistributions in binary form must reproduce the above ! copyright notice, this list of conditions and the following ! disclaimer in the documentation and/or other materials provided ! with the distribution. ! * Neither the name of the copyright owner nor the names of any ! other contributors may be used to endorse or promote products ! derived from this software without specific prior written ! permission. ! ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT ! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR ! A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT ! OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ! LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, ! DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY ! THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ! (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE ! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ! ! CREATION DATE: 03-DEC-1990 ! ! MODIFICATION HISTORY: ! ! 03-DEC-1990 V1.0 Madison Initial coding. ! 11-MAR-1992 V1.1 Madison Update for MX V3.1. ! 15-MAY-1992 V1.2 Madison Correct "restat" typo. Add full_convert. !-- */ #include descrip #include string #include stdio #include ssdef #include str$routines #include lib$routines #define NICK_TO_ADDRESS 1 #define USERNAME_TO_NICK 2 #define NAME_COUNT 2 static char *user [] = {"SMYTHE", "SYSTEM"}; static char *nick [] = {"J.Smythe", "System.Manager"}; #define FULL_COUNT 2 static char *full_user[] = {"MADISON", "SHANDY_P"}; static char *full_nick[] = {"madison@tgv.com", "Peter_Shandy@portulaca-purple-passion.balaclava.edu"}; struct context { struct dsc$descriptor localnode; }; /* !++ ! ! ROUTINE NAME: INIT ! ! FUNCTIONAL DESCRIPTION: ! ! Allocates and initializes context block for subsequent name conversions. ! ! RETURNS: cond_value, longword (unsigned), write only, by value ! ! PROTOTYPE: ! ! INIT ctxptr ! ! ctxptr: pointer, longword (unsigned), modify, by reference ! ! IMPLICIT INPUTS: None. ! ! IMPLICIT OUTPUTS: None. ! ! COMPLETION CODES: ! ! SS$_NORMAL: normal successful completion. ! ! SIDE EFFECTS: ! ! None. !-- */ unsigned int init (struct context **ctx) { int ctxsize; $DESCRIPTOR(mx_node_name,"MX_NODE_NAME"); ctxsize = sizeof(struct context); lib$get_vm (&ctxsize, ctx); (*ctx)->localnode.dsc$b_dtype = DSC$K_DTYPE_T; (*ctx)->localnode.dsc$b_class = DSC$K_CLASS_D; (*ctx)->localnode.dsc$w_length = 0; (*ctx)->localnode.dsc$a_pointer = NULL; lib$sys_trnlog (&mx_node_name, 0, &(*ctx)->localnode); return SS$_NORMAL; } /* init */ /* !++ ! ! ROUTINE NAME: CONVERT ! ! FUNCTIONAL DESCRIPTION: ! ! Converts username -> nickname or nickname -> RFC821-address. ! ! NB: You MUST use STR$ routines to copy result to OUTSTR parameter ! to ensure proper operation!!!! ! ! You _may_ safely assume that INSTR is compatible with a DTYPE_T, ! CLASS_S (standard fixed-length) string descriptor. ! ! RETURNS: cond_value, longword (unsigned), write only, by value ! ! PROTOTYPE: ! ! CONVERT ctxptr, code, instr, outstr ! ! ctxptr: pointer, longword (unsigned), modify, by reference ! code: longword_unsigned, longword (unsigned), read only, by reference ! instr: char_string, character string, read only, by descriptor (fixed) ! outstr: char_string, character string, write only, by descriptor ! ! IMPLICIT INPUTS: None. ! ! IMPLICIT OUTPUTS: None. ! ! COMPLETION CODES: ! ! SS$_NORMAL: normal successful completion. ! ! SIDE EFFECTS: ! ! None. !-- */ unsigned int convert (struct context **ctx, int *code, struct dsc$descriptor *instr, struct dsc$descriptor *outstr) { struct dsc$descriptor tmp, tmp2; size_t count; int i, j, retstat; $DESCRIPTOR(lbrack, "<"); $DESCRIPTOR(rbrack, ">"); $DESCRIPTOR(atsign, "@"); count = instr -> dsc$w_length; tmp.dsc$b_dtype = DSC$K_DTYPE_T; tmp.dsc$b_class = DSC$K_CLASS_D; tmp.dsc$w_length = 0; tmp.dsc$a_pointer = NULL; tmp2.dsc$b_dtype = DSC$K_DTYPE_T; tmp2.dsc$b_class = DSC$K_CLASS_S; switch (*code) { /* !++ ! Local alias -> address ! ! This code should return a status of SS$_NORMAL if an alias is found, ! 0 otherwise. ! ! If an alias is found, the resulting string MUST BE IN RFC821 format: ! ! ! ! >>>>>> EVEN IF THE ADDRESS IS FOR THE LOCAL HOST (so you have to ! look up MX_NODE_NAME and tack it on after the translated name, ! if you're just doing a local-host user directory). !-- */ case NICK_TO_ADDRESS: retstat = 0; str$copy_dx(&tmp, instr); for (i = 0; i < NAME_COUNT; i++) { tmp2.dsc$w_length = strlen(nick[i]); tmp2.dsc$a_pointer = nick[i]; if (str$case_blind_compare(instr, &tmp2) == 0) { j = strlen(user[i]); str$copy_r(&tmp, &j, user[i]); str$concat(outstr, &lbrack, &tmp, &atsign, &(*ctx)->localnode, &rbrack); retstat = SS$_NORMAL; break; } } break; /* !++ ! Username -> Alias ! ! Return sucess status ONLY if you are actually converting the ! username to an alias! Otherwise, return a non-success status code. ! ! For compatibility with the name_conversion interface prior to ! MX V3.1, you should copy the input string to the output string ! when you return a non-success status. ! !-- */ case USERNAME_TO_NICK: retstat = 0; str$copy_dx(outstr, instr); /* for pre-V3.1 compatibility */ for (i = 0; i < NAME_COUNT; i++) { tmp2.dsc$w_length = strlen(user[i]); tmp2.dsc$a_pointer = user[i]; if (str$case_blind_compare(instr, &tmp2) == 0) { j = strlen(nick[i]); str$copy_r(outstr, &j, nick[i]); retstat = SS$_NORMAL; break; } } break; } return retstat; } /* convert */ /* !++ ! ! ROUTINE NAME: FULL_CONVERT ! ! FUNCTIONAL DESCRIPTION: ! ! Converts username -> alias address (full address substitution) ! ! Unlike the CONVERT routine, FULL_CONVERT converts a username ! to a complete RFC822-type address. You must be running MX V3.1C ! or later to use this feature. ! ! NB: You MUST use STR$ routines to copy result to OUTSTR parameter ! to ensure proper operation!!!! ! ! You _may_ safely assume that INSTR is compatible with a DTYPE_T, ! CLASS_S (standard fixed-length) string descriptor. ! ! RETURNS: cond_value, longword (unsigned), write only, by value ! ! PROTOTYPE: ! ! FULL_CONVERT ctxptr, code, instr, outstr ! ! ctxptr: pointer, longword (unsigned), modify, by reference ! code: longword_unsigned, longword (unsigned), read only, by reference ! instr: char_string, character string, read only, by descriptor (fixed) ! outstr: char_string, character string, write only, by descriptor ! ! IMPLICIT INPUTS: None. ! ! IMPLICIT OUTPUTS: None. ! ! COMPLETION CODES: ! ! SS$_NORMAL: normal successful completion. ! ! SIDE EFFECTS: ! ! None. !-- */ unsigned int full_convert (struct context **ctx, int *code, struct dsc$descriptor *instr, struct dsc$descriptor *outstr) { struct dsc$descriptor tmp, tmp2; size_t count; int i, j, retstat; $DESCRIPTOR(lbrack, "<"); $DESCRIPTOR(rbrack, ">"); $DESCRIPTOR(atsign, "@"); count = instr -> dsc$w_length; tmp.dsc$b_dtype = DSC$K_DTYPE_T; tmp.dsc$b_class = DSC$K_CLASS_D; tmp.dsc$w_length = 0; tmp.dsc$a_pointer = NULL; tmp2.dsc$b_dtype = DSC$K_DTYPE_T; tmp2.dsc$b_class = DSC$K_CLASS_S; if (*code != USERNAME_TO_NICK) return 0; /* !++ ! Username -> alias (full address conversion) ! ! Return sucess status ONLY if you are actually converting the ! username to an alias! Otherwise, return a non-success status code. ! !-- */ retstat = 0; for (i = 0; i < FULL_COUNT; i++) { tmp2.dsc$w_length = strlen(full_user[i]); tmp2.dsc$a_pointer = full_user[i]; if (str$case_blind_compare(instr, &tmp2) == 0) { j = strlen(full_nick[i]); str$copy_r(outstr, &j, full_nick[i]); retstat = SS$_NORMAL; break; } } return retstat; } /* full_convert */ /* !++ ! ! ROUTINE NAME: CLEANUP ! ! FUNCTIONAL DESCRIPTION: ! ! Deallocates context block allocated by init routine. ! ! RETURNS: cond_value, longword (unsigned), write only, by value ! ! PROTOTYPE: ! ! CLEANUP ctxptr ! ! ctxptr: pointer, longword (unsigned), modify, by reference ! ! IMPLICIT INPUTS: None. ! ! IMPLICIT OUTPUTS: None. ! ! COMPLETION CODES: ! ! SS$_NORMAL: normal successful completion. ! ! SIDE EFFECTS: ! ! None. !-- */ unsigned int cleanup (struct context **ctx) { int ctxsize; str$free1_dx(&(*ctx)->localnode); ctxsize = sizeof(struct context); lib$free_vm (&ctxsize, ctx); *ctx = NULL; return SS$_NORMAL; } /* cleanup */