/***************************************************************************
 *                                                                         *
 *   GALALIAS.C                                                            *
 *                                                                         *
 *   Copyright (c) 1994-1997 Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Alias names for users (from User-ID by default, intercepted by        *
 *   GALGWI.DLL if installed).                                             *
 *                                                                         *
 *                                        - RNStein  8/2/94                *
 *                                                                         *
 *   Changed so aliasing is supported whether or not MG/I is installed,    *
 *   and sealed up alias "leaks" to prevent e-mail from being stolen.      *
 *                                                                         *
 *                                        - C. Dunn  10/18/95              *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "gcspsrv.h"
#include "gme.h"
#include "alias.h"
#include "galalias.h"
#ifdef UNIX
#include <pwd.h>
#endif
#include <limits.h>

#define FILREV "$Revision: 28 $"

                                   /* Btrieve record key definitions       */
#define USRKEY 0                   /*   key 0 (User-ID) for .DAT file      */
#define CNVKEY 1                   /*   key 1 (Converted User-ID) for file */
#define ALAKEY 2                   /*   key 2 (alias) for .DAT file        */

                                   /* lonrou() action codes                */
#define PROMPT 1                   /*   prompt user for Internet alias     */
#define REMIND 2                   /*   give user reminder about alias     */
#define IGNORE 3                   /*   make no mention of alias           */

/* bit array manipulation macros */
#define FLGARR_SIZE(n)   (((n)+(CHAR_BIT-1))/CHAR_BIT)
#define FLGARR_SET(a,n)  ((a)[(n)/CHAR_BIT] |= (1<<((n)&(CHAR_BIT-1))))
#define FLGARR_CLR(a,n)  ((a)[(n)/CHAR_BIT] &=~(1<<((n)&(CHAR_BIT-1))))
#define FLGARR_TEST(a,n) ((a)[(n)/CHAR_BIT] &  (1<<((n)&(CHAR_BIT-1))))

/* this struct must stay above prototypes! */
struct alsrec {                    /* Btrieve record layout                */
     CHAR userid[UIDSIZ];          /*   User-ID (key 0)                    */
     CHAR convid[UIDSIZ];          /*   alias form of User-ID (key 1)      */
     CHAR alias[ALSSIZ];           /*   Internet alias (key 2)             */
     GBOOL sntmsg;                 /*   have we sent conflict message?     */
};

GBOOL alslon(VOID);
GBOOL lonachk(const CHAR *userid,struct alsrec *alsrecp);
VOID crthook(const struct usracc *pAcct);
VOID inihook(const CHAR *userid);
GBOOL alsinp(VOID);
VOID alsdla(CHAR *uid);
VOID alsfin(VOID);
VOID alsrst(VOID);
VOID alsAnno(VOID);
VOID alsRead(INT direction,struct saunam *dpknam);
VOID alsWrite(struct saunam *dpknam,USHORT length,VOID *value);
VOID formDpkResp(struct alsrec *pAlias);
CHAR *tvar_alias(VOID);
VOID addals(const CHAR *alias,struct alsrec *alsrecp,const CHAR *userid);
GBOOL valals(const CHAR *alias);
GBOOL uidcfl(const CHAR *userid);
GBOOL alscfl(const CHAR *userid,const CHAR *alias);
GBOOL alssys(VOID);
VOID alspmt(INT nwsstt);
VOID getals(VOID);
GBOOL newAlias(const CHAR *userid,CHAR *alias,struct alsrec *pRec);
VOID dspals(VOID);
VOID dspuid(VOID);
VOID kilals(VOID);
CHAR *cnvuid(const CHAR *userid);
GBOOL dftAliasInUse(const CHAR *userid,const CHAR *alias);
CHAR *stubals(CHAR *userid);
CHAR *stubusr(CHAR *alias);
CHAR *aofu(CHAR *userid);
CHAR *uofa(CHAR *alias);

/* functions from Active HTML module */
extern VOID ahInit(VOID);
extern VOID ahClose(VOID);

GBOOL (*alsinuse)(const CHAR *userid,const CHAR *alias)=dftAliasInUse;
CHAR *(*alsofusr)(CHAR *userid)=aofu;
CHAR *(*usrofals)(CHAR *alias)=uofa;
CHAR *(*oaofu)(CHAR *userid)=stubals;
CHAR *(*ouofa)(CHAR *alias)=stubusr;

VOID (*oldrst)(VOID);              /* old channel reset handler            */

DFAFILE *alsbb=NULL;               /* Btrieve pointer to GALALS2.DAT       */

HMCVFILE alsmb;                    /* file handle for GALALIAS.MCV         */

GBOOL useals;                      /* use aliasing on the system?          */
GBOOL inLogon=FALSE;               /* are we in A/A logon routine?         */

CHAR *alskey;                      /* key required for sysop alias funcs   */
CHAR *csAliasKey;                  /* key required for sysop alias funcs   */
CHAR *annoaid;                     /* App-ID to send alias announcement    */
CHAR *annocmd;                     /* cmd line for client to config alias  */
CHAR *cflflg;                      /* array of conflict-msg-sent flags     */

INT alsstt;                        /* alias module state number            */
INT alslgn;                        /* action to take at logon              */

struct module alsmodule={          /* module interface block               */
     "",                           /*    name used to refer to this module */
     alslon,                       /*    user logon supplemental routine   */
     alsinp,                       /*    input routine if selected         */
     dfsthn,                       /*    status-input routine if selected  */
     NULL,                         /*    "injoth" routine for this module  */
     NULL,                         /*    user logoff supplemental routine  */
     NULL,                         /*    hangup (lost carrier) routine     */
     NULL,                         /*    midnight cleanup routine          */
     alsdla,                       /*    delete-account routine            */
     alsfin                        /*    finish-up (sys shutdown) routine  */
};

struct alsusr {                    /* per-user alias information (vda)     */
     struct alsrec alsrec;         /*   User-ID/alias information          */
     GBOOL lonfin;                 /*   are we finished with lonrou?       */
     CHAR dftinp;                  /*   default input character            */
};

#define alsptr ((struct alsusr *)vdaptr)

struct agent alsagent={            /* GALALIAS C/S agent                   */
     ALSAPID,                      /*   appid                              */
     alsRead,                      /*   read-dynapak function pointer      */
     alsWrite,                     /*   write-dynapak function pointer     */
     NULL,                         /*   file xfer-done function pointer    */
     NULL                          /*   abort-request function pointer     */
};

VOID
init__galalias(VOID)               /* initialize alias handler             */
{
     struct alsrec als;
     static GBOOL didinit=FALSE;

     if (didinit) {
          return;
     }
     didinit=TRUE;
     init__galme();
     hook_createacct(crthook);
     hook_gme(GMEHOOK_NOT_INIUSR,(voidfunc)inihook);
     stzcpy(alsmodule.descrp,gmdnam("galalias.mdf"),MNMSIZ);
     alsstt=register_module(&alsmodule);
     register_agent(&alsagent);
     oldrst=hdlrst;
     hdlrst=alsrst;
     dfaMode(PRIMBV);
     alsbb=dfaOpen("galals2.dat",sizeof(struct alsrec),NULL);
     alsmb=opnmsg("galalias.mcv");
     alskey=stgopt(ALSKEY);
     csAliasKey=stgopt(CSALSKY);
     useals=ynopt(USEALS);
     if ((alslgn=tokopt(ALSLGN,"PROMPT","REMIND","IGNORE",NULL)) == 0) {
          alslgn=IGNORE;
     }
     annoaid=stgopt(ANNOAID);
     annocmd=stgopt(ANNOCMD);
     hook_announce(alsAnno);
     cflflg=(CHAR *)alczer(FLGARR_SIZE(nterms));
     register_textvar("ALIAS",tvar_alias);
     dclvda(sizeof(struct alsusr));
     if (!dfaAcqEQ(&als,NOALCV,CNVKEY)) {
          setmem(&als,sizeof(struct alsrec),0);
          stlcpy(als.userid,NOALID,UIDSIZ);
          stlcpy(als.convid,NOALCV,UIDSIZ);
          dfaInsert(&als);
     }
#ifndef GCDOS
     ahInit();
#endif // GCDOS
}

VOID EXPORT
initwc__galalias(VOID)
{
     init__galalias();
}

CHAR *
tvar_alias(VOID)                   /* text var. routine for user's alias   */
{
     CHAR tmpuid[UIDSIZ];

     *tmpuid='\0';
     if (isuidc(usaptr->userid[0])) {
          stlcpy(tmpuid,usaptr->userid,UIDSIZ);
     }
     else if (usaptr->userid[0] == '(' && samend(usaptr->userid,")")) {
          stlcpy(tmpuid,&usaptr->userid[1],UIDSIZ);
          tmpuid[strlen(tmpuid)-1]='\0';
     }
     if (isuidc(tmpuid[0])) {
          return((*alsofusr)(tmpuid));
     }
     return("");
}

GBOOL
alslon(VOID)                       /* logon supplemental routine           */
{
     GBOOL ok2remind=TRUE;
     GBOOL rc=FALSE;

     inLogon=TRUE;
     setmbk(alsmb);
     dfaSetBlk(alsbb);
     switch (usrptr->substt) {
     case 0:
          inigmeu();
          if (lonachk(usaptr->userid,&alsptr->alsrec)) {
               clrprf();
               prfmsg(useals ? ALSEMLE : ALSEMLN);
               outprf(usrnum);
               ok2remind=FALSE;
          }
          if (useals) {
               switch (alslgn) {
               case PROMPT:
                    if (alsptr->alsrec.alias[0] == '\0') {
                         prfmsg(GTWALS);
                         prfmsg(usrptr->substt=ENTALS);
                         outprf(usrnum);
                         rc=TRUE;
                    }
                    break;
               case REMIND:
                    if (ok2remind && alsptr->alsrec.alias[0] == '\0') {
                         prfmsg(RMDALS);
                         outprf(usrnum);
                    }
                    break;
               case IGNORE:
                    break;
               }
          }
          break;
     default:
          rc=alsinp();
          break;
     }
     inLogon=FALSE;
     return(rc);
}

VOID
crthook(                           /* create account notification handler  */
const struct usracc *pAcct)        /*   completed user account info        */
{
     inihook(pAcct->userid);
}

VOID
inihook(                           /* alias inigmeu() hook handler         */
const CHAR *userid)                /*   User-ID being initialized          */
{                                  /*   (handles C/S and POP3 users)       */
     struct alsrec alsrec;

     if (!inLogon && alsbb != NULL) {
          lonachk(userid,&alsrec);
     }
}

GBOOL                              /*   TRUE if a conflict was detected    */
lonachk(                           /* at logon, check for lack of alias    */
const CHAR *userid,                /*   User-ID to check                   */
struct alsrec *alsrecp)            /*   pointer to in-memory alias record  */
{
     GBOOL rc;
     struct message *pMsg;

     setmbk(alsmb);
     dfaSetBlk(alsbb);
     if (!dfaAcqEQ(alsrecp,userid,USRKEY)) {
          addals(NULL,alsrecp,userid);
     }
     if (alsrecp->convid[0] == '\0' && alsrecp->alias[0] == '\0'
      && !alsrecp->sntmsg) {
          pMsg=(struct message *)vdatmp;
          memset(pMsg,0,sizeof(struct message));
          strcpy(pMsg->from,"Sysop");
          strcpy(pMsg->to,userid);
          stlcpy(pMsg->topic,stpans(getmsg(CFLTPC)),TPCSIZ);
          pMsg->flags|=PRIMSG;
          pMsg->forum=EMLID;
          simpsnd(pMsg,stpans(getmsg(useals ? CFLMSGE : CFLMSGN)),NULL);
          alsrecp->sntmsg=TRUE;
          dfaGetEQ(NULL,alsrecp->userid,USRKEY);
          dfaUpdate(alsrecp);
          rc=TRUE;
          if (!inLogon) {
               FLGARR_SET(cflflg,usrnum);
          }
     }
     else {
          /* This foolishness with cflflg[] and inLogon causes lonachk()   */
          /* to return TRUE if the error message was generated as part of  */
          /* this session, but not as a result of a logon announcement-    */
          /* related call.  This way the user still gets the logon conflict*/
          /* announcement, even if some other module has already caused    */
          /* the message to be generated by calling inigmeu().             */
          rc=(inLogon && FLGARR_TEST(cflflg,usrnum));
          if (rc) {
               FLGARR_CLR(cflflg,usrnum);
          }
     }
     dfaRstBlk();
     rstmbk();
     return(rc);
}

GBOOL
alsinp(VOID)                       /* input routine                        */
{
     setmbk(alsmb);
     dfaSetBlk(alsbb);
     chkdft(alsptr->dftinp);
     if (margc == 0 || (usrptr->flags&INJOIP)) {
          if (usrptr->substt == ENTALS && usrptr->usrcls == SUPLON
            && !(usrptr->flags&INJOIP)) {
               prfmsg(NONSET);
               outprf(usrnum);
               return(FALSE);
          }
          else {
               numcat=maxcat+1;
               alspmt(usrptr->substt);
          }
     }
     else if (margc == 1 && sameas(margv[0],"X")) {
          btumil(usrnum,DFTIMX);
          switch (usrptr->substt) {
          case INTRO:
          case INTROS:
          case INTPMT:
          case INTPMTS:
               return(FALSE);
          case FNDALS:
          case REMALS:
               clrxrf();
          default:
               if (usrptr->usrcls == SUPLON && usrptr->substt == ENTALS) {
                    prfmsg(NONSET);
                    outprf(usrnum);
                    return(FALSE);
               }
               if (!(usrptr->flags&CONCEX)) {
                    numcat=maxcat+1;
                    alspmt(INTPMT);
               }
               condex();
          }
     }
     else {
          do {
               bgncnc();
               switch (usrptr->substt) {
               case 0:
                    cncchr();
                    if (!useals && !haskey(alskey)) {
                         prfmsg(ALSNEN2);
                         prfmsg(ALSCONT);
                         outprf(usrnum);
                         return(FALSE);
                    }
                    usrptr->flags&=~X2MAIN;
                    alspmt(INTRO);
                    break;
               case INTRO:
               case INTROS:
               case INTPMT:
               case INTPMTS:
                    switch (cncchr()) {
                    case '?':
                         cncall();
                         alspmt(INTRO);
                         break;
                    case 'H':
                         cncall();
                         prfmsg(ALSHLP);
                         alspmt(usrptr->substt);
                         break;
                    case 'E':
                         if (!dfaAcqEQ(&alsptr->alsrec,usaptr->userid,USRKEY)
                              || alsptr->alsrec.alias[0] == '\0') {
                              alspmt(ENTALS);
                         }
                         else {
                              cncall();
                              prfmsg(HAVALS);
                              alspmt(INTPMT);
                         }
                         break;
                    case 'D':
                         if (dfaAcqEQ(&alsptr->alsrec,usaptr->userid,USRKEY)
                           && alsptr->alsrec.alias[0] != '\0') {
                              prfmsg(YOUALS,alsptr->alsrec.alias);
                         }
                         else {
                              prfmsg(NOHALS);
                         }
                         alspmt(INTPMT);
                         break;
                    case 'F':
                         if (alssys()) {
                              alspmt(FNDALS);
                         }
                         break;
                    case 'C':
                         if (alssys()) {
                              alspmt(FNDUID);
                         }
                         break;
                    case 'R':
                         if (alssys()) {
                              alspmt(REMALS);
                         }
                         break;
                    default:
                         cncall();
                         prfmsg(CNOTIL);
                         alspmt(usrptr->substt);
                    }
                    break;
               case ENTALS:
                    getals();
                    break;
               case FNDALS:
                    dspals();
                    break;
               case FNDUID:
                    dspuid();
                    break;
               case REMALS:
                    kilals();
                    break;
               default:
                    cncall();
                    shocst("GALALIAS SUBSTT ERROR!",
                           "User-ID: %s - Substt: %d",
                           usaptr->userid,usrptr->substt);
                    return(FALSE);
               }
          } while (!endcnc());
     }
     outprf(usrnum);
     return(!alsptr->lonfin);
}

VOID
alsdla(                            /* delete account routine               */
CHAR *uid)                         /*   User-ID being deleted              */
{
     dfaSetBlk(alsbb);
     if (dfaAcqEQ(NULL,uid,USRKEY)) {
          dfaDelete();
     }
}

VOID
alsfin(VOID)                       /* finish-up (system shutdown) routine  */
{
#ifndef GCDOS
     ahClose();
#endif // GCDOS
     clsmsg(alsmb);
     dfaClose(alsbb);
     alsbb=NULL;
}

VOID
alsrst(VOID)                       /* alias module reset-channel handler   */
{
     FLGARR_CLR(cflflg,usrnum);
     (*oldrst)();
}

VOID
alsAnno(VOID)                      /* need to configure alias announcer    */
{
     struct alsrec tmpals;

     if (!haskey(csAliasKey)) {
          addanno("");
          return;
     }
     inLogon=TRUE;
     setmbk(alsmb);
     inigmeu();
     clrprf();
     if (lonachk(usaptr->userid,&tmpals)) {
          if (useals) {
               prfmsg(ALSEMLE);
               addannom(prfbuf,annoaid,annocmd);
          }
          else {
               prfmsg(ALSEMLN);
               addanno(prfbuf);
          }
     }
     else if (useals && alslgn != IGNORE && *tmpals.alias == '\0') {
          prfmsg(ANNOMSG);
          addannom(prfbuf,annoaid,annocmd);
     }
     else {
          addanno("");
     }
     inLogon=FALSE;
}

VOID
alsRead(                           /* C/S agent read vector                */
INT direction,                     /*   read direction                     */
struct saunam *dpknam)             /*   dynapak name being read            */
{
     struct alsrec tmpals;

     if (stdchk(csAliasKey)) {
          setmbk(alsmb);
          if (direction == 0 && sameas("alias",dpknam->suffix)
           && (sameas(usaptr->userid,dpknam->usrid) || haskey(alskey))) {
               dfaSetBlk(alsbb);
               if (!dfaAcqEQ(&tmpals,dpknam->usrid,USRKEY)) {
                    addals(NULL,&tmpals,dpknam->usrid);
               }
               dfaRstBlk();
               formDpkResp(&tmpals);
               rsp2read(NULL,STGLEN,rsptmp,NULL);
               return;
          }
     }
     rejectreq();
}

VOID
alsWrite(                          /* C/S agent write vector               */
struct saunam *dpknam,             /*   dynapak name being written         */
USHORT length,                     /*   length of dynapak                  */
VOID *value)                       /*   contents of dynapak                */
{
     struct alsrec tmpals;

     (VOID)length;
     if (stdchk(csAliasKey)) {
          setmbk(alsmb);
          if (sameas("alias",dpknam->suffix)
           && (sameas(usaptr->userid,dpknam->usrid) || haskey(alskey))) {
               clrprf();
               if (useals) {
                    if (newAlias(dpknam->usrid,value,&tmpals)) {
                         formDpkResp(&tmpals);
                         rsp2write(TRUE,STGLEN,rsptmp,NULL);
                         return;
                    }
               }
               else {
                    prfmsg(ALSNEN2);
               }
               r2wprf(FALSE);
               return;
          }
     }
     rejectreq();
}

VOID
formDpkResp(                       /* form response to alias read/write    */
struct alsrec *pAlias)             /*   alias info to use                  */
{
     strcpy(rsptmp,"OK\t");
     if (useals) {
          strcat(strcat(rsptmp,pAlias->alias),"\t");
     }
     strcat(rsptmp,strrpl(pAlias->convid,'*','.'));
}

VOID
addals(                            /* add User-ID and alias to .DAT file   */
const CHAR *alias,                 /*   alias for user (NULL for new)      */
struct alsrec *alsrecp,            /*   pointer to in-memory alias record  */
const CHAR *userid)                /*   User-ID to add                     */
{
     dfaSetBlk(alsbb);
     memset(alsrecp,0,sizeof(struct alsrec));
     if (!uidcfl(userid)) {
          stlcpy(alsrecp->convid,cnvuid(userid),UIDSIZ);
     }
     if (!NULSTR(alias)) {
          stlcpy(alsrecp->alias,alias,ALSSIZ);
     }
     dfaSetBlk(accbb);
     if (dfaQueryEQ(userid,0)) {
          userid=(const CHAR *)accbb->key;
     }
#ifdef DEBUG
     else {
          ASSERTM(FALSE,spr("Invalid User-ID passed to addals(): \"%s\"",userid));
     }
#endif // DEBUG
     dfaRstBlk();
     stlcpy(alsrecp->userid,userid,UIDSIZ);
     if (dfaAcqEQ(NULL,alsrecp->userid,USRKEY)) {
          dfaUpdate(alsrecp);
     }
     else {
          dfaInsert(alsrecp);
     }
     dfaRstBlk();
}

GBOOL                              /*   returns TRUE if valid alias        */
valals(                            /* is this alias valid for the system?  */
const CHAR *alias)                 /*   alias to check                     */
{
     while (*alias != '\0' && isalnum(*alias)) {
          ++alias;
     }
     return(*alias == '\0');
}

GBOOL                              /*   returns TRUE if conflict           */
uidcfl(                            /* does User-ID have alias conflict?    */
const CHAR *userid)                /*   User-ID to check                   */
{
     GBOOL rc;
     CHAR tmpuid[UIDSIZ];
     struct alsrec tmprec;

     dfaSetBlk(alsbb);
     stlcpy(tmpuid,cnvuid(userid),UIDSIZ);
     rc=((dfaAcqEQ(&tmprec,tmpuid,CNVKEY) && !sameas(userid,tmprec.userid))
      || (dfaAcqEQ(&tmprec,tmpuid,ALAKEY) && !sameas(userid,tmprec.userid)));
#ifdef UNIX
     rc=rc || getpwnam(tmpuid) != NULL;
#endif
     dfaRstBlk();
     return(rc);
}

GBOOL                              /*   returns TRUE if conflict           */
alscfl(                            /* does alias have conflict?            */
const CHAR *userid,                /*   User-ID to check                   */
const CHAR *alias)                 /*   alias to check                     */
{
     GBOOL rc;
     struct alsrec tmprec;

     dfaSetBlk(alsbb);
     rc=((dfaAcqEQ(&tmprec,alias,ALAKEY) && !sameas(userid,tmprec.userid))
      || (!sameas(userid,alias) && uidxst(alias)));
#ifdef UNIX
     rc=rc || getpwnam(tmpuid) != NULL;
#endif
     dfaRstBlk();
     return(rc);
}

GBOOL                              /*   returns TRUE if user has alskey    */
alssys(VOID)                       /* does user have alskey?               */
{
     if (haskey(alskey)) {
          return(TRUE);
     }
     cncall();
     prfmsg(CNOTIL);
     alspmt(usrptr->substt);
     return(FALSE);
}

VOID
alspmt(                            /* set new substt and prompt user       */
INT nwsstt)                        /*   new substate for user              */
{
     usrptr->substt=nwsstt;
     if (!morcnc()) {
          switch (usrptr->substt) {
          case INTRO:
               btumil(usrnum,DFTIMX);
               condex();
               if (haskey(alskey)) {
                    usrptr->substt=INTROS;
               }
               prfmsg(usrptr->substt);
               break;
          case INTPMT:
               btumil(usrnum,DFTIMX);
               condex();
               if (haskey(alskey)) {
                    usrptr->substt=INTPMTS;
               }
               prfmsg(usrptr->substt);
               break;
          case ENTALS:
          case FNDUID:
               btumil(usrnum,ALSSIZ-1);
               prfmsg(nwsstt);
               break;
          case FNDALS:
          case REMALS:
               btumil(usrnum,UIDSIZ-1);
               prfmsg(nwsstt);
               break;
          default:
               prfmsg(nwsstt);
               break;
          }
          alsptr->dftinp=getdft();
     }
}

VOID
getals(VOID)                       /* handle input of user alias           */
{
     cncall();
     rstrin();
     if (newAlias(usaptr->userid,input,&alsptr->alsrec)) {
          prfmsg(ADDALS);
          if (usrptr->usrcls == SUPLON) {
               alsptr->lonfin=TRUE;
          }
          else {
               alspmt(INTPMT);
          }
     }
     else {
          alspmt(ENTALS);
     }
}

GBOOL                              /*   returns TRUE if successful         */
newAlias(                          /* validate and create/update an alias  */
const CHAR *userid,                /*   User-ID of alias being created     */
CHAR *alias,                       /*   new alias candidate                */
struct alsrec *pRec)               /*   buffer to create in                */
{
     if (NULSTR(alias)) {
          if (uidcfl(userid)) {
               if (useals) {
                    prfmsg(ALSCFLE);
               }
               else {
                    prfmsg(ALSCFLN);
               }
               return(FALSE);
          }
     }
     else {
          if (strlen(alias) > ALSSIZ-1) {
               prfmsg(LONGALS);
               return(FALSE);
          }
          if (profan(alias) > 0 && !uhskey(userid,syskey)) {
               prfmsg(NOPROF);
               return(FALSE);
          }
          strlwr(alias);
          if (!valals(alias)) {
               prfmsg(BADALS);
               return(FALSE);
          }
          if ((*alsinuse)(userid,alias)) {
               prfmsg(ALSINU);
               return(FALSE);
          }
     }
     addals(alias,pRec,userid);
     return(TRUE);
}

VOID
dspals(VOID)                       /* display alias for specific User-ID   */
{
     CHAR *alias;

     switch (hdluid(cncall())) {
     case UIDFND:
          alias=(*alsofusr)(uidxrf.userid);
          if (alias[0] != '(') {
               if (alias[0] != '\0') {
                    prfmsg(THEALS,uidxrf.userid,alias);
               }
               else {
                    prfmsg(NOSALS,uidxrf.userid);
               }
          }
          else {
               prfmsg(NOFALS,uidxrf.userid);
          }
          alspmt(INTPMT);
          break;
     case UIDPMT:
          alspmt(usrptr->substt);
          break;
     case UIDCAL:
          alsptr->dftinp=languages[clingo]->yes[0];
          break;
     }
}

VOID
dspuid(VOID)                       /* display User-ID for specific alias   */
{
     CHAR *userid;

     cncall();
     rstrin();
     if ((userid=(*usrofals)(input)) != NULL) {
          prfmsg(THEUID,input,userid);
     }
     else {
          prfmsg(NOHUID,input);
     }
     alspmt(INTPMT);
}

VOID
kilals(VOID)                       /* delete an alias from the .DAT file   */
{
     struct alsrec alstmp;

     switch (hdluid(cncall())) {
     case UIDFND:
          if (dfaAcqEQ(&alstmp,uidxrf.userid,USRKEY)) {
               setmem(alstmp.alias,ALSSIZ,0);
               dfaUpdate(&alstmp);
               prfmsg(DELALS,uidxrf.userid);
          }
          else {
               prfmsg(NODALS,uidxrf.userid);
          }
          alspmt(INTPMT);
          break;
     case UIDPMT:
          alspmt(usrptr->substt);
          break;
     case UIDCAL:
          alsptr->dftinp=languages[clingo]->yes[0];
          break;
     }
}

CHAR *                             /*   returns pointer to converted ID    */
cnvuid(                            /* convert User-ID to generic alias     */
const CHAR *userid)                /*   User-ID to convert                 */
{
     INT i;
     static CHAR uid[UIDSIZ];

     stzcpy(uid,userid,UIDSIZ);
     for (i=0 ; i < strlen(uid) ; i++) {
          if (uid[i] == ' ' || uid[i] == '.' || uid[i] == '_') {
               uid[i]='*';
          }
     }
     return(uid);
}

GBOOL
dftAliasInUse(                     /* default alias-in-use tester          */
const CHAR *userid,                /*   User-ID being tested               */
const CHAR *alias)                 /*   alias being tested                 */
{
     return(alscfl(userid,alias)
         || (sameas(alias,"Sysop") && !sameas(userid,"Sysop"))
         || sameas(alias,"From"));
}

CHAR *
stubals(                           /* stub alias:  form from User-ID       */
CHAR *userid)
{
     static CHAR mofid[MAXADR];
     CHAR *cp;

     strcpy(mofid,userid);
     while ((cp=strchr(mofid,' ')) != NULL) {
          *cp='.';
     }
     return(mofid);
}

CHAR *
stubusr(                           /* stub User-ID:  can't find            */
CHAR *alias)
{
     (VOID)alias;
     return(NULL);
}

CHAR *                             /*   returns pointer to User-ID         */
uofa(                              /* find User-ID for given alias         */
CHAR *alias)                       /*   alias to find User-ID for          */
{
     static struct alsrec als;

     dfaSetBlk(alsbb);
     if (*alias != '\0'
      && (dfaAcqEQ(&als,alias,ALAKEY)
       || dfaAcqEQ(&als,cnvuid(alias),CNVKEY))) {
          dfaRstBlk();
          return(als.userid);
     }
     dfaRstBlk();
     return(NULL);
}

CHAR *                             /*   returns pointer to alias           */
aofu(                              /* find alias for given User-ID         */
CHAR *userid)                      /*   User-ID to find alias for          */
{
     GBOOL found;
     static struct alsrec als;

     dfaSetBlk(alsbb);
     found=dfaAcqEQ(&als,userid,USRKEY);
     dfaRstBlk();
     if (found) {
          if (useals && als.alias[0] != '\0') {
               return(als.alias);
          }
          if (sameas(userid,als.userid)) {
               return(strrpl(als.convid,'*','.'));
          }
     }
     return(stlcpy(als.convid,NOALCV,UIDSIZ));
}
