/******************************************************************************* PROTO Root module of alternate protocol stub for VMS MAIL-11 V3.0 Edit Edit date By Reason 04 23-May-96 DTH Added C dispatch table, removing need for external macro PROTO_ACTION module 03 26-Feb-96 LEB Added support for AXP and standarized calls using C's variable arguments. 02 30-Aug-89 NMdS Updated to support mail protocol version 2.1. 01 27-Oct-87 NMdS New *******************************************************************************/ #ifdef __DECC #pragma module PROTO "V01.04" #else #module PROTO "V01.04" #endif #include /* standard I/O definitions */ #include /* system service definitions */ #include /* variable argument list */ /* The following two global values are made UNIVERSAL by the LINK options file * (PROTO_[VAX|AXP].OPT). They are read and checked by VMSMAIL. If the protocol * versions do not match, VMSMAIL will abort with an appropriate message. */ #ifdef __DECC #pragma message save #pragma message disable (globalext) #endif globalvalue MAIL$C_PROT_MAJOR = 2 ; /* Mail protocol major version */ globalvalue MAIL$C_PROT_MINOR = 1 ; /* Mail protocol minor version */ #ifdef __DECC #pragma message restore #endif /* * Declare forwards for the functions used in the dispatch table. * Note that we use the old K&R "forward" reference, rather than full ANSI * functional prototypes .. if we use full functional prototypes, then the * function must be explicitly cast in the dispatch table to a "function * returning long with an unknown number of parameters", which is a pain.. */ extern long PROTO_OUT_CONNECT (); extern long PROTO_OUT_SENDER (); extern long PROTO_OUT_CKUSER (); extern long PROTO_OUT_TO (); extern long PROTO_OUT_SUBJ (); extern long PROTO_OUT_FILE (); extern long PROTO_OUT_CKSEND (); extern long PROTO_OUT_DEACCESS (); extern long PROTO_IN_CONNECT (); extern long PROTO_IN_SENDER (); extern long PROTO_IN_CKUSER (); extern long PROTO_IN_TO (); extern long PROTO_IN_SUBJ (); extern long PROTO_IN_FILE (); extern long PROTO_IO_READ (); extern long PROTO_IO_WRITE (); extern long PROTO_IN_CC (); extern long PROTO_OUT_CC (); extern long PROTO_IN_ATTRIBS (); extern long PROTO_OUT_ATTRIBS (); /* * Define Dispatch table */ typedef long (*LPFN) (); LPFN mai$r_action[] = {&PROTO_OUT_CONNECT ,&PROTO_OUT_SENDER ,&PROTO_OUT_CKUSER ,&PROTO_OUT_TO ,&PROTO_OUT_SUBJ ,&PROTO_OUT_FILE ,&PROTO_OUT_CKSEND ,&PROTO_OUT_DEACCESS ,&PROTO_IN_CONNECT ,&PROTO_IN_SENDER ,&PROTO_IN_CKUSER ,&PROTO_IN_TO ,&PROTO_IN_SUBJ ,&PROTO_IN_FILE ,&PROTO_IO_READ ,&PROTO_IO_WRITE ,&PROTO_IN_CC ,&PROTO_OUT_CC ,&PROTO_IN_ATTRIBS ,&PROTO_OUT_ATTRIBS }; /* * MAIL$PROTOCOL: - Good luck debugging this if it breaks!!! * * This is the entry point for all alternate protocol routines. The * "mai$l_operation" flag determines which function is required. This is * checked for validity, and then looked up in a table of action routine * addresses. If an entry is found, then we call the specified routine with * the same argument list as MAIL$PROTOCOL was called with. We have to do it * this way as MAIL$PROTOCOL is called with a different set of parameters for * each function. The only thing that is common to all functions is the first * two parameters; "arg_1" is actually the address of a context longword that * we can write to, and "mai$l_operation" is the actual operation code, a * LNK_C_xxx code from LNKDEF in module MAILDEF. This routine is the only * UNIVERSAL function that is declared by the LINK options file * (PROTO_[VAX|AXP].OPT). In total, only three UNIVERSAL symbols are * declared; this routine and the two protocol version numbers above. */ MAIL$PROTOCOL( long *mai$al_context, /* Context field for protocol */ long mai$l_operation, /* Type of operation */ ...) { int status ; va_list ap ; /* argument pointer */ LPFN mai$a_routine ; /* Action routine to call */ /* * NOTE: * * You can write a value into mai$al_context, eg. the address of a memory * block. This will then be passed to all action routines as the first * parameter. This is the only way session dependant information may be * passed between routines. Initially, *mai$al_context = 0. */ /* * Check for out of range LNK_C_* function codes */ if ((mai$l_operation < 0) || (mai$l_operation >= (sizeof(mai$r_action) / sizeof(mai$r_action[0])))) { return(SS$_BADPARAM) ; } /* * Check for any unimplemented (by our program) LNK_C_* function codes */ if ((mai$a_routine = mai$r_action[mai$l_operation]) == 0) { return(SS$_NOENTRY) ; } /* * Start variable length argument processing after the two known fixed parameters */ va_start (ap, mai$l_operation) ; /* * Call the appropriate function to process mai$l_operation code (LNK_C_*), * passing the two fixed parameters and any trailing variable parameters */ status = mai$a_routine (mai$al_context, mai$l_operation, ap) ; /* * Clean up variable argument processing */ va_end (ap) ; /* * All done ... wasn't it simple ? */ return (status) ; }