/***************************************************************************
 *                                                                         *
 *   PAGE.C                                                                *
 *                                                                         *
 *   Copyright (c) 1997      Galacticomm, Inc.    All Rights Reserved.     *
 *                                                                         *
 *   Baseline paging support.                                              *
 *                                                                         *
 *                                            - Bill Hyatt 2/14/97         *
 *                                                                         *
 ***************************************************************************/

#include "gcomm.h"
#include "majorbbs.h"
#include "oprlow.h"
#include "wgspag.h"

#define FILREV "$Revision: 19 $"

// results of ck4pfn() calls
#define NOPFN  0                   // input had no profanity
#define WARNED 1                   // user was given warning message
#define HUNGUP 2                   // user was hung up on

#define MINPGINT 1                 // minimum configurable page interval
#define MAXPGINT 99                // maximum configurable page interval

// global paging-related routine pointers
INT
     (*parsePageCmdRou)(CHAR *pageCmdBuf,VOID *pageCmdInfo)=NULL,
                                   // parse page command
     (*cspagerou)(CHAR *to,CHAR *msg)=NULL,// c/s page routine
     (*gpirouUid)(const CHAR *userid)=NULL,      // get user's page interval
     (*pagerouUid)(const CHAR *from,const CHAR *to,CHAR *msg)=NULL,// send page
     (*pagesetUid)(const CHAR *userid)=NULL,        // set on/off/ok setting
     (*pageHowmnyHook)(CHAR *stg,GBOOL samas, CHAR* match)=NULL;
VOID
     (*spagesetUid)(const CHAR *userid,GBOOL on,GBOOL ok)=NULL,// set on/off/ok setting
     (*hdlPageCmdRou)(INT pageCode,VOID *pageCmdInfo)=NULL,
                                   // handle page command
     (*setPageIntRou)(const CHAR *userid,INT pageIntMins)=NULL,// set page interval
     (*pageShowRou)(const CHAR *userid)=NULL;    // show page settings

GBOOL
     (*pageIgnoredRou)(const CHAR *userid,const CHAR *uid)=NULL,
                                   // user's pages begin ignored?
     (*ignorePageRou)(const CHAR *userid, const CHAR *uid)=NULL,// ignore a user's pages
     (*allowPageRou)(const CHAR *userid, const CHAR *uid)=NULL,// allow a user's pages
     (*canPageHook)(const CHAR *userid)=NULL,
     (*pageOutputHook)(const CHAR *userid)=NULL;

CHAR*
     (*pagePrspowHook)(CHAR *start,INT mnum,INT *count,CHAR *match)=NULL;

struct pageInfo*
     (*pageGetInfoHook)(const CHAR* userid)=NULL;

// For backward compatability
INT
     (*gpirou)(INT usn)=NULL,      // get user's page interval
     (*pagerou)(CHAR *to,CHAR *msg)=NULL,// send page
     (*pageset)(VOID)=NULL;        // set on/off/ok setting
VOID
     (*spageset)(GBOOL on,GBOOL ok)=NULL;// set on/off/ok setting

// ***


INT gpagint;                       // global page interval, use if gpirou==NULL

CHAR *pagekey,                     // key required to use paging
     *noignkey;                    // key required to not be ignored

INT dftpop,                        // default page option for new users
    defpgint;                      // default page interval for new users

struct pageInfo *pageptr;          // global pointer to user's page info

HMCVFILE pagemb;                   // paging configuration file

static
INT sopbel;                        // pitch of console page beep

static
struct pageInfo *ThePageInfo;      // array of per-user page info

static
VOID *ThePageCmdInfo;              // global page cmd info buffer

static INT gloPage(VOID);
static VOID pagetck(VOID);
static INT parsePageCmd(CHAR *pageCmdBuf,VOID *pageCmdInfo);
static VOID hdlPageCmd(INT pageCode,VOID *pageCmdInfo);
static INT sendPageUid(const CHAR *uidfrom, const CHAR *uidto,CHAR *pagmsg);
static INT getPageSettingUid(const CHAR *userid);
static VOID setPageSettingUid(const CHAR *userid, GBOOL on,GBOOL ok);
static VOID pageShow(const CHAR *userid);
static INT getPageIntervalUid(const CHAR *userid);
static VOID setPageInterval(const CHAR *userid, INT pageIntMins);
static GBOOL ignorePage(const CHAR *userid, const CHAR *uid);
static GBOOL allowPage(const CHAR *userid, const CHAR *uid);
static GBOOL pageIgnored(const CHAR *userid, const CHAR *uid);
static INT howmny(CHAR *stg,GBOOL samas, CHAR *match);
static CHAR *prspow(CHAR *start,INT mnum,INT *count, CHAR *match);
static INT ck4pfn(VOID);
static VOID chlblnk(INT unum,GBOOL blink);
static GBOOL canPage(const CHAR *userid);
static struct pageInfo* pageGetInfo(const CHAR* userid);
static GBOOL pageOutput(const CHAR *userid);

static INT sendPage(CHAR *uidto,CHAR *pagmsg);
static INT getPageSetting(VOID);
static VOID setPageSetting(GBOOL on,GBOOL ok);
static INT getPageInterval(INT usn);
static CHAR* strparin(const CHAR* stg);

VOID
initPaging(VOID)                   // initialize baseline paging
{
     pagemb=opnmsg("wgspag.mcv");

     ThePageInfo=(struct pageInfo *)alcblok(nterms,sizeof(struct pageInfo));
     ThePageCmdInfo=(VOID *)alczer(PAGBUFSIZ);

     parsePageCmdRou=parsePageCmd;
     hdlPageCmdRou=hdlPageCmd;
     pagerou=sendPage;
     pageset=getPageSetting;
     spageset=setPageSetting;
     gpirou=getPageInterval;

     pagerouUid=sendPageUid;
     pagesetUid=getPageSettingUid;
     spagesetUid=setPageSettingUid;
     gpirouUid=getPageIntervalUid;

     setPageIntRou=setPageInterval;
     pageShowRou=pageShow;
     ignorePageRou=ignorePage;
     allowPageRou=allowPage;
     pageIgnoredRou=pageIgnored;
     pageHowmnyHook=howmny;
     pagePrspowHook=prspow;
     canPageHook=canPage;
     pageGetInfoHook=pageGetInfo;
     pageOutputHook=pageOutput;

     globalcmd(gloPage);

     defpgint=numopt(DEFPGINT,MINPGINT,MAXPGINT);
     gpagint=defpgint*60; // maintain backwards compatibility...
     dftpop=tokopt(DFTPOP,"OK","OFF","ON",NULL);
     sopbel=numopt(SOPBEL,1,2000);
     pagekey=stgopt(PAGEKEY);
     noignkey=stgopt(NOIGNKEY);

     rtkick(PAGETCKINT,pagetck);
}

static VOID
pagetck(VOID)                      // paging real-time kick routine
{
     for (usrnum=0 ; usrnum < nterms ; usrnum++) {
          pageptr=pageGetInfoNum(usrnum);
          if (pageptr->pagedCtr > 0) {
               pageptr->pagedCtr--;
          }
          if (pageptr->pagedConsCtr > 0) {
               if ((pageptr->pagedConsCtr-=1) == 0) {
                    chlblnk(usrnum,FALSE);
               }
          }
     }
     rtkick(PAGETCKINT,pagetck);
}

static INT
gloPage(VOID)                      // handle global paging command
{
     if (margc >= 1 && sameas(margv[0],"/p")) {
          (*hdlPageCmdRou)((*parsePageCmdRou)(NULL,ThePageCmdInfo),ThePageCmdInfo);
          outprf(usrnum);
          return(1);
     }
     return(0);
}

VOID
pageLogon(VOID)
{
     memset((pageptr=pageGetInfoNum(usrnum)),0,sizeof(struct pageInfo));
     pageLoadRecord(usaptr->userid,pageptr);
}

VOID
pageLoadRecord(
const CHAR* userid,
struct pageInfo* pPageInfo)
{
     struct pageInfoDisk pageInfDisk;

     setmem(&pageInfDisk,sizeof(struct pageInfoDisk),0);
     stlcpy(pageInfDisk.userid,userid,UIDSIZ);
     stlcpy(pageInfDisk.modnam,PAGMNM,MNMSIZ);
     dfaSetBlk(genbb);
     if (dfaAcqEQ(&pageInfDisk,&pageInfDisk,0)) {
          pPageInfo->pageInt=pageInfDisk.pageInt;
          pPageInfo->pageSts=pageInfDisk.pageSts;
          pPageInfo->nIgnore=pageInfDisk.nIgnore;
          movmem(pageInfDisk.ignList,pPageInfo->ignList,pPageInfo->nIgnore*IGNLSIZ);
     }
     else {
          setmem(pPageInfo,sizeof(struct pageInfo),0);
          pPageInfo->pageInt=MIN2PINT(defpgint);
          pPageInfo->pageSts=dftpop;
     }
     dfaRstBlk();
}

VOID
pageHup(VOID)                    // handle hangup for paging
{
     pageptr=pageGetInfoNum(usrnum);
     pageSaveRecord(usaptr->userid,pageptr);
}

VOID
pageSaveRecord(
const CHAR* userid,
struct pageInfo* pPageInfo)
{
     struct pageInfoDisk pageInfDisk;
     GBOOL recxst;

     setmem(&pageInfDisk,sizeof(struct pageInfoDisk),0);
     stlcpy(pageInfDisk.userid,userid,UIDSIZ);
     stlcpy(pageInfDisk.modnam,PAGMNM,MNMSIZ);
     dfaSetBlk(genbb);
     recxst=dfaAcqEQ(&pageInfDisk,&pageInfDisk,0);
     pageInfDisk.pageInt=pPageInfo->pageInt;
     pageInfDisk.pageSts=pPageInfo->pageSts;
     pageInfDisk.nIgnore=pPageInfo->nIgnore;
     movmem(pPageInfo->ignList,pageInfDisk.ignList,pPageInfo->nIgnore*IGNLSIZ);
     if (recxst) {
          dfaUpdateV(&pageInfDisk,
                     fldoff(pageInfoDisk,ignList)+(pPageInfo->nIgnore*IGNLSIZ));
     }
     else {
          dfaInsertV(&pageInfDisk,
                     fldoff(pageInfoDisk,ignList)+(pPageInfo->nIgnore*IGNLSIZ));
     }
     dfaRstBlk();
     setmem(pPageInfo,sizeof(struct pageInfo),0);
}

VOID
pageDel(                           // handle delete-account for paging
CHAR *uid)                         //   userid being deleted
{
     struct pageInfoDisk pagInfDisk;

     dfaSetBlk(genbb);
     stlcpy(pagInfDisk.userid,uid,UIDSIZ);
     stlcpy(pagInfDisk.modnam,PAGMNM,MNMSIZ);
     if (dfaAcqEQ(&pagInfDisk,&pagInfDisk,0)) {
          dfaDelete();
     }
     dfaRstBlk();
}

INT                                //   returns command to perform
parsePageCmd(                      // parse a page command
CHAR *pageCmdBuf,                  //   page command input (NULL=use input)
VOID *pageCmdInfo)                 //   buffer to return page command info
{
     INT pageInt;
     CHAR *uid;

     if (pageCmdBuf != NULL) {
          clrinp();
          stlcpy(input,pageCmdBuf,INPSIZ);
          parsin();
     }
     if (margc == 1 || sameas(margv[1],"?")) {
          return(PRS_PAGE_FORMAT);
     }
     if (sameas(margv[1],"ok")) {
          return(PRS_PAGE_TOK);
     }
     if (sameas(margv[1],"off")) {
          return(PRS_PAGE_TOF);
     }
     if (sameas(margv[1],"on")) {
          return(PRS_PAGE_TON);
     }
     if (sameas(margv[1],"show")) {
          return(PRS_PAGE_SHOW);
     }
     if (strlen(margv[1]) < 3 && alldgs(margv[1])) {
          if ((pageInt=atoi(margv[1])) < MINPGINT) {
               pageInt=MINPGINT;
          }
          if (pageInt > MAXPGINT) {
               pageInt=MAXPGINT;
          }
          *((INT *)pageCmdInfo)=pageInt;
          return(PRS_PAGE_SETINT);
     }
     rstrin();
     if (sameto("ignore ",margv[1])) {
          if ((uid=uidCaps(margv[2])) != NULL) {
               stlcpy((CHAR *)pageCmdInfo,uid,PAGBUFSIZ);
               return(PRS_PAGE_IGNORE);
          }
          return(PRS_PAGE_NOTFND);
     }
     if (sameto("allow ",margv[1])) {
          if ((uid=uidCaps(margv[2])) != NULL) {
               stlcpy((CHAR *)pageCmdInfo,uid,PAGBUFSIZ);
               return(PRS_PAGE_ALLOW);
          }
          return(PRS_PAGE_NOTFND);
     }
     return(pageUserMessage(NULL,pageCmdInfo));
}

INT                                //   returns command to perform
pageUserMessage(                   // parse a page - no command
CHAR* pageCmdBuf,                  //   page command input (NULL=use input)
VOID* pageCmdInfo)                 //   buffer to return page command info
{
     INT count;
     CHAR uidto[PAGBUFSIZ];
     CHAR* start=uidto;
     CHAR* pagmsg;

     if (pageCmdBuf != NULL) {
          clrinp();
          stlcpy(input,pageCmdBuf,INPSIZ);
          parsin();
     }
     if ((count=(*pageHowmnyHook)(margv[1],TRUE,uidto)) == 1) {
          pagmsg="";
     }
     else {
          pagmsg=(*pagePrspowHook)(margv[1],1,&count,uidto);
     }
     if (count == 0) {
          if (sameas(margv[1],"Sysop") || sameto("Sysop ",margv[1])
           || sameas(margv[1],"Sysop:") || sameto("Sysop: ",margv[1])) {
               stlcpy((CHAR *)pageCmdInfo, "Sysop\t", PAGBUFSIZ);
               stlcat((CHAR *)pageCmdInfo, (margc > 2 ? margv[2] : "")
                     ,PAGBUFSIZ);
               return(PRS_PAGE_USER);
          }
          rstrin();
          stlcpy((CHAR *)pageCmdInfo,margv[1],PAGBUFSIZ);
          parsin();
          return(PRS_PAGE_NOTON);
     }
     if (count == NEEDCO) {
          stlcpy((CHAR *)pageCmdInfo,margv[1],PAGBUFSIZ);
          return(PRS_PAGE_NEEDCO);
     }
     if (count != 1) {
          strcpy((CHAR *)pageCmdInfo,margv[1]);
          return(PRS_PAGE_AMBIG);
     }
     if (strchr(uidto,'(') == uidto) {
          CHAR* ptr;
          start++;
          if ((ptr=strchr(start,')')) != 0) {
               *ptr='\0';
          }
     }
     sprintf((CHAR *)pageCmdInfo,"%s%c%s",start,TAB,pagmsg);
     return(PRS_PAGE_USER);
}

static VOID
hdlPageCmd(                        // carry out page command
INT pageCode,                      //   command to do
VOID *pageCmdInfo)                 //   additional info buffer
{
     CHAR uid[PAGBUFSIZ];

     setmbk(pagemb);
     switch (pageCode) {
     case PRS_PAGE_FORMAT:
          prfmlt(PAGFMT2);
          break;
     case PRS_PAGE_TOK:
          (*spagesetUid)(usaptr->userid,FALSE,TRUE);
          break;
     case PRS_PAGE_TOF:
          (*spagesetUid)(usaptr->userid,FALSE,FALSE);
          break;
     case PRS_PAGE_TON:
          (*spagesetUid)(usaptr->userid,TRUE,FALSE);
          break;
     case PRS_PAGE_SHOW:
          (*pageShowRou)(usaptr->userid);
          break;
     case PRS_PAGE_SETINT:
          (*setPageIntRou)(usaptr->userid,*((INT *)pageCmdInfo));
          break;
     case PRS_PAGE_IGNORE:
          (*ignorePageRou)(usaptr->userid,(CHAR *)pageCmdInfo);
          break;
     case PRS_PAGE_ALLOW:
          (*allowPageRou)(usaptr->userid,(CHAR *)pageCmdInfo);
          break;
     case PRS_PAGE_USER:
          stlcpy(uid,itemidx((CHAR *)pageCmdInfo,0),PAGBUFSIZ);
          (*pagerouUid)(usaptr->userid,uid,itemidx((CHAR *)pageCmdInfo,1));
          break;
     case PRS_PAGE_NOTFND:
          prfmlt(UNOTFND);
          break;
     case PRS_PAGE_NOTON:
          prfmlt(PAGNON,(CHAR *)pageCmdInfo);
          break;
     case PRS_PAGE_NEEDCO:
          prfmlt(PNEEDCO,(CHAR *)pageCmdInfo);
          break;
     case PRS_PAGE_AMBIG:
          prfmlt(PAMBIG,(CHAR *)pageCmdInfo);
          break;
     }
     rstmbk();
}

static
GBOOL
canPage(
const CHAR* userid)
{
     return(onsys(userid));
}

struct pageInfo*
pageGetInfoNum(                    /* get page info struct by channel      */
INT unum)                          /*   channel number to get              */
{
     return((struct pageInfo *)ptrblok(ThePageInfo,unum));
}

static
struct pageInfo*
pageGetInfo(
const CHAR* userid)
{
     if (onsysn(userid,1)) {
          return(pageGetInfoNum(othusn));
     }
     return(NULL);
}

static
GBOOL
pageOutput(
const CHAR* userid)
{
     if (!onsys(userid) || !injoth()) {
          return(FALSE);
     }
     return(TRUE);
}
                                   //   0=didn't page,1=paged,2=paged console,
static INT                         //   -1=no such userid,-2=from user is invalid
sendPageUid(                       // send a page to a user
const CHAR *uidfrom,               //   user page is from
const CHAR *uidto,                 //   user to send page to
CHAR *pagmsg)                      //   message, if any
{
     if ((pageptr=(*pageGetInfoHook)(uidfrom)) == NULL) {
          return(0);
     }
     setmbk(pagemb);
     if (usrptr->flags&INVISB) {
          prfmlt(URINV);
          rstmbk();
          return(0);
     }
     if (!uhskey(strparin(uidfrom),pagekey) && !sameas(uidto,"Sysop")) {
          prfmlt(NOPAGKEY);
          rstmbk();
          howbuy();
          return(0);
     }
     (*setpfn)(pagmsg);
     if (ck4pfn() != NOPFN) {
          rstmbk();
          return(0);
     }
     if (!(*canPageHook)(uidto)) {
          if (sameas(uidto,"Sysop")) {
               if (pagmsg[0] != '\0') {
                    belper(sopbel);
                    printf("\7");
                    prfmlt(PAGEOK,"Sysop (at main console)");
                    psmatms((CHAR*)pagmsg);
                    chlblnk(usrnum,TRUE);
                    pageptr->pagedConsCtr=MIN2PINT(1); // hack - should be 2
                    rstmbk();
                    return(2);
               }
               else {
                    prfmlt(NEEDMSG);
                    rstmbk();
                    return(0);
               }
          }
          prfmlt(PAGNON, uidto);
          rstmbk();
          return(0);
     }
     if ((pageptr=(*pageGetInfoHook)(uidto)) == NULL) {
          prfmlt(PAGNON, uidto);
          rstmbk();
          return(0);
     }
     if (pageptr->pageSts == PAGE_OFF) {
          prfmlt(PAGOFF,othuap->userid);
          rstmbk();
          return(0);
     }
     if ((*pageIgnored)(uidto,strparin(uidfrom))) {
          prfmlt(URIGN,uidto);
          rstmbk();
          return(0);
     }
     if (pageptr->pageSts != PAGE_OK && pageptr->pagedCtr > 0) {
         prfmlt(NOPAGYET,uidto,PINT2MIN(pageptr->pageInt));
         rstmbk();
         return(0);
     }
     if (pagmsg == NULL || *pagmsg == '\0') {
          prfmlt(PAGNOTFY,strparin(uidfrom),module[usrptr->state]->descrp);
     }
     else {
          prfmlt(PAGMSG,strparin(uidfrom),module[usrptr->state]->descrp,pagmsg);
     }

     if ((onsysn(uidto,1) && othusp->flags&ISGCSU) && cspagerou != NULL) {
          clrmlt();
          if ((*cspagerou)((CHAR*)strparin(uidfrom),pagmsg)) {
               pageptr->pagedCtr=pageptr->pageInt;
               prfmsg(PAGEOK,othuap->userid);
               rstmbk();
               return(1);
          }
          prfmsg(PAGNPS,othuap->userid);
          rstmbk();
          return(0);
     }
     for (pagmsg=prfbuf ; *pagmsg != '\0' ; pagmsg++) {
          if (*pagmsg == '\n') {
               *pagmsg=' ';
          }
     }
     if ((*pageOutputHook)(uidto)) {
          clrmlt();
          pageptr->pagedCtr=pageptr->pageInt;
          prfmsg(PAGEOK,uidto);
          rstmbk();
          return(1);
     }
     prfmsg(PAGNPS,uidto);
     rstmbk();
     return(0);
}

static INT
sendPage(
CHAR* userid,
CHAR* pagmsg)
{
     // using uacoff(usrnum) rather then usaptr, as we don't
     // want to make any assumptions about whether curusr() was called
     // for backward compatability
     return(pagerouUid(uacoff(usrnum)->userid,userid,pagmsg));
}

static INT
getPageSettingUid(
const CHAR* userid)               // get a user's page status setting
{
     return((*pageGetInfoHook)(userid)->pageSts);
}

static INT
getPageSetting(VOID)
{
     // using uacoff(usrnum) rather then usaptr, as we don't
     // want to make any assumptions about whether curusr() was called
     // for backward compatability
     return(pagesetUid(uacoff(usrnum)->userid));
}


static VOID
setPageSettingUid(                 // set a user's page status setting
const CHAR* userid,
GBOOL on,                          //   on/off?
GBOOL ok)                          //   page set to ok?
{
     if ((pageptr=(*pageGetInfoHook)(userid)) == NULL) {
          catastro("pageGetInfoHook returned NULL in setPageSettingUid! (PAGE.C)");
          return;
     }
     setmbk(pagemb);
     if (on) {
          pageptr->pageSts=PAGE_ON;
          prfmlt(PAGTON,PINT2MIN(pageptr->pageInt));
     }
     else if (ok) {
          pageptr->pageSts=PAGE_OK;
          prfmlt(PAGTOK,PINT2MIN(pageptr->pageInt));
     }
     else {
          pageptr->pageSts=PAGE_OFF;
          prfmlt(PAGTOF);
     }
     rstmbk();
}

static VOID
setPageSetting(
GBOOL on,
GBOOL off)
{
     // using uacoff(usrnum) rather then usaptr, as we don't
     // want to make any assumptions about whether curusr() was called
     // for backward compatability
     spagesetUid(uacoff(usrnum)->userid,on,off);
}

static VOID
pageShow(
const CHAR* userid)                 // show user's page settings
{
     INT i;

     struct pageInfo* pPageInfo;

     if ((pPageInfo=(*pageGetInfoHook)(userid)) == NULL) {
          catastro("pageGetInfoHook returned NULL in pageShow! (PAGE.C)");
          return;
     }
     setmbk(pagemb);
     prfmlt(CURPSET
           ,(pPageInfo->pageSts == PAGE_ON
             ? "ON"
             : (pPageInfo->pageSts == PAGE_OFF ? "OFF" : "OK")
            )
           ,PINT2MIN(pPageInfo->pageInt));
     if (pPageInfo->nIgnore > 0) {
          prfmlt(IGNHDR);
          for (i=0 ; i < pPageInfo->nIgnore ; i++) {
               prfmlt(IGNUSR,pPageInfo->ignList[i]);
          }
     }
     rstmbk();
}

static INT
getPageIntervalUid(                   // get a user's page interval
const CHAR* userid)                   //   user num to get for
{
     return(PINT2MIN(pageGetInfo(userid)->pageInt));
}

static INT
getPageInterval(
INT usn)
{
     return(gpirouUid(uacoff(usn)->userid));
}

static VOID
setPageInterval(                   // set current user's page interval
const CHAR* userid,
INT pageIntMins)                   //   minutes for page interval
{
     if (pageIntMins < MINPGINT) {
          pageIntMins=MINPGINT;
     }
     if (pageIntMins > MAXPGINT) {
          pageIntMins=MAXPGINT;
     }
     (*pageGetInfoHook)(userid)->pageInt=MIN2PINT(pageIntMins);
     setmbk(pagemb);
     prfmlt(PGINTSET,pageIntMins);
     rstmbk();
}

static GBOOL
ignorePage(                        /* ignore pages from a user             */
const CHAR *userid,                /*   User-ID to modify page info for    */
const CHAR *uid)                   /*   User-ID to allow                   */
{
     setmbk(pagemb);
     if (!uidxst(uid) || (pageptr=(*pageGetInfoHook)(userid)) == NULL) {
          prfmlt(UNOTFND);
          rstmbk();
          return(FALSE);
     }
     if (uhskey(uid,noignkey)) {
          prfmlt(CANTIGN,uid);
          rstmbk();
          return(FALSE);
     }
     if (pageptr->nIgnore >= MAXIGN) {
          prfmlt(ATMAXIGN,MAXIGN);
          rstmbk();
          return(FALSE);
     }
     if (!(*pageIgnoredRou)(userid,uid)) {
          stlcpy(pageptr->ignList[pageptr->nIgnore],uid,IGNLSIZ);
          pageptr->nIgnore++;
     }
     prfmlt(PAGIGN,uid);
     rstmbk();
     return(TRUE);
}

static GBOOL
allowPage(                         /* allow pages from a user              */
const CHAR *userid,                /*   User-ID to modify page info for    */
const CHAR *uid)                   /*   User-ID to allow                   */
{
     INT i;

     if (!uidxst(uid) || (pageptr=(*pageGetInfoHook)(userid)) == NULL) {
          setmbk(pagemb);
          prfmlt(UNOTFND);
          rstmbk();
          return(FALSE);
     }
     for (i=0 ; i < pageptr->nIgnore ; i++) {
          if (sameas(uid,pageptr->ignList[i])) {
               movmem(pageptr->ignList[i+1],pageptr->ignList[i],
                      (pageptr->nIgnore-(i+1))*IGNLSIZ);
               pageptr->nIgnore--;
               pageptr->ignList[pageptr->nIgnore][0]='\0';
               break;
          }
     }
     setmbk(pagemb);
     prfmlt(PAGALW,uid);
     rstmbk();
     return(TRUE);
}

static GBOOL                       //   TRUE=pagee is ingoring pager
pageIgnored(                       // is pagee ignoring pager?
const CHAR *userid,                //   userid of pagee
const CHAR *uid)                   //   userid to check
{
     INT i;

     if ((pageptr=(*pageGetInfoHook)(userid)) == NULL) {
          return(FALSE);
     }
     for (i=0 ; i < pageptr->nIgnore ; i++) {
          if (sameas(uid,pageptr->ignList[i])) {
               return(TRUE);
          }
     }
     return(FALSE);
}

static INT
howmny(                            // number of people starting w/ stg?
CHAR *stg,                         // stg to use in sameto() test
GBOOL samas,                       // take sameas() as a return(1)?
CHAR* match)
{
     INT cnt=0,dstusn;

     for (othusn=0 ; othusn < nterms ; othusn++) {
          othusp=usroff(othusn);
          othuap=uacoff(othusn);
          if (!samas && !(othusp->flags&INVISB) && othusp->usrcls >= SUPLON
           && sameto(stg,othuap->userid)) {
               dstusn=othusn;
               cnt++;
          }
          if (samas && sameas(stg,othuap->userid)) {
               cnt=1;
               dstusn=othusn;
               break;
          }
     }
     if (cnt == 1) {
          othusn=dstusn;
          othusp=usroff(othusn);
          othuap=uacoff(othusn);
          if (match != NULL) {
               stlcpy(match,othuap->userid,PAGBUFSIZ);
          }
          ASSERT(match != NULL);
     }
     return(cnt);
}

static CHAR *
prspow(                            // parse destination of some action
CHAR *start,
INT mnum,
INT *count,
CHAR *match)
{
     INT lastcnt=0;
     CHAR* msg;
     GBOOL done=FALSE;

     parsin();
     while (!done && (mnum < margc)) {
          msg=margn[mnum];
          if (*(msg-1) == ':') {
               *(msg-1)='\0';
               *count=(*pageHowmnyHook)(start,TRUE,match);
               *(msg-1)=':';
               mnum++;
               done=TRUE;
          }
          else {
               *count=(*pageHowmnyHook)(start,FALSE,match);
          }
          if (*count == 0) {
               done=TRUE;
          }
          else {
               lastcnt=*count;
          }
          if (!done) {
               if (mnum < (margc-1)) {
                    margn[mnum][0]=' ';
               }
               mnum++;
          }
     }
     rstrin();
     if ((*count != 1) && (lastcnt > 0)) {
          *count=lastcnt;
     }
     if (mnum == margc) {
          return("");
     }
     else {
          return(margv[mnum]);
     }
}

static INT
ck4pfn(VOID)                       /* check for profanity and deal with it */
{
     setmbk(pagemb);
     if (usrptr->pfnacc > MAXPFN) {
          byenow(NO_MESSAGE);
          rstmbk();
          return(HUNGUP);
     }
     if (pfnlvl >= 2 && usrptr->pfnacc > WRNPFN) {
          prfmsg(RAUNCH);
          rstmbk();
          return(WARNED);
     }
     if (pfnlvl > 2) {
          prfmsg(PFNWRD);
          rstmbk();
          return(WARNED);
     }
     rstmbk();
     return(NOPFN);
}

static VOID
chlblnk(                           // turn blinking on/off on user list
INT unum,                          //   channel to change
GBOOL blink)                       //   TRUE=blink, FALSE=no blink
{
     CHAR tmpbuf[LGNSIZ];
     struct uidisp *chlptr;

     chlptr=&uidarr[channel[unum]];
     stlcpy(tmpbuf,chlptr->labl,LGNSIZ);
     shochl(tmpbuf,chlptr->sing,baudat(usroff(unum)->baud,blink));
}

static CHAR*
strparin(
const CHAR* stg)
{
     static CHAR newstg[PAGBUFSIZ];
     size_t stglen;
     CHAR *ptr=newstg;

     if (stg == NULL) {
          return("");
     }
     stlcpy(newstg,stg,PAGBUFSIZ);
     stglen=strlen(newstg);
     if (newstg[stglen-1] == ')') {
          newstg[stglen-1]='\0';
     }
     if (newstg[0] == '(') {
          newstg[0]='\0';
          ptr=&newstg[1];
     }
     return(ptr);
}

