home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1998 September / PCO_0998.ISO / filesbbs / dos / sbbs_src.exe / SBBS / CHAT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-04-13  |  47.0 KB  |  1,713 lines

  1. #line 1 "CHAT.C"
  2.  
  3. /* Developed 1990-1997 by Rob Swindell; PO Box 501, Yorba Linda, CA 92885 */
  4.  
  5. /****************************************/
  6. /* Local and Node-to-Node Chat routines */
  7. /****************************************/
  8.  
  9. #include "sbbs.h"
  10.  
  11. #define PCHAT_LEN 1000        /* Size of Private chat file */
  12.  
  13. int getnodetopage(int all, int telegram);
  14.  
  15.  
  16. char *weekday[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday"
  17.                 ,"Saturday"};
  18. char *month[]={"January","February","March","April","May","June"
  19.             ,"July","August","September","October","November","December"};
  20.  
  21.  
  22. /****************************************************************************/
  23. /* Chat between local keyboard and remote user on current node.                */
  24. /* Called from inkey (inkey is then re-entrant)                                */
  25. /****************************************************************************/
  26. void localchat()
  27. {
  28.     uchar    str[256],act;
  29.     int con=console;    /* save console state */
  30.     time_t     beg=time(NULL);
  31.  
  32. console&=~(CON_L_ECHOX|CON_R_ECHOX);    /* turn off X's */
  33. console|=(CON_L_ECHO|CON_R_ECHO);        /* make sure echo is enabled */
  34. nosound();
  35. sys_status&=~SS_SYSPAGE;
  36. act=action;                    /* save the user's current action */
  37. action=NODE_LCHT;
  38. bprintf(text[SysopIsHere],sys_op);
  39. while(sys_status&SS_LCHAT && online) {
  40.     SYNC;
  41.     getstr(str,78,K_WRAP|K_MSG); }
  42. bputs(text[EndOfChat]);
  43. now=time(NULL);
  44. if(!(sys_status&SS_USERON))
  45.     answertime=now;
  46. starttime+=now-beg;   /* credit user for time in chat */
  47. RESTORELINE;
  48. action=act;
  49. console=con;                    /* restore console */
  50. }
  51.  
  52. void sysop_page(void)
  53. {
  54.     int i;
  55.  
  56. for(i=0;i<total_pages;i++)
  57.     if(chk_ar(page[i]->ar,useron))
  58.         break;
  59. if(i<total_pages) {
  60.     bprintf(text[PagingGuru],sys_op);
  61.     external(cmdstr(page[i]->cmd,nulstr,nulstr,NULL)
  62.         ,page[i]->misc&IO_INTS ? EX_OUTL|EX_OUTR|EX_INR
  63.             : EX_OUTL); }
  64. else if(sys_misc&SM_SHRTPAGE) {
  65.     bprintf(text[PagingGuru],sys_op);
  66.     for(i=0;i<10 && !lkbrd(1);i++) {
  67.         beep(1000,200);
  68.         mswait(200);
  69.         outchar('.'); }
  70.     CRLF; }
  71. else {
  72.     sys_status^=SS_SYSPAGE;
  73.     bprintf(text[SysopPageIsNow]
  74.         ,sys_status&SS_SYSPAGE ? text[ON] : text[OFF]);
  75.     nosound();    }
  76. }
  77.  
  78. /****************************************************************************/
  79. /* Returns 1 if user online has access to channel "channum"                 */
  80. /****************************************************************************/
  81. char chan_access(uint cnum)
  82. {
  83.  
  84. if(!total_chans || cnum>=total_chans || !chk_ar(chan[cnum]->ar,useron)) {
  85.     bputs(text[CantAccessThatChannel]);
  86.     return(0); }
  87. if(!(useron.exempt&FLAG('J')) && chan[cnum]->cost>useron.cdt+useron.freecdt) {
  88.     bputs(text[NotEnoughCredits]);
  89.     return(0); }
  90. return(1);
  91. }
  92.  
  93. void privchat(void)
  94. {
  95.     uchar    str[128],ch,c,*p,localbuf[5][81],remotebuf[5][81]
  96.             ,localline=0,remoteline=0,localchar=0,remotechar=0
  97.             ,*sep="\1w\1h─────[\1i\1r%c\1n\1h]────┤ "
  98.                 "\1yPrivate Chat - \1rCtrl-C to Quit \1y- "
  99.                 "Time Left: \1g%-8s\1w"
  100.                 " ├────[\1i\1b%c\1n\1h]─────";
  101.     int     in,out,i,j,n,done,echo=1,x,y,activity;
  102.     node_t    node;
  103.  
  104. n=getnodetopage(0,0);
  105. if(!n)
  106.     return;
  107. if(n==node_num) {
  108.     bputs(text[NoNeedToPageSelf]);
  109.     return; }
  110. getnodedat(n,&node,0);
  111. if(node.action==NODE_PCHT && node.aux!=node_num) {
  112.     bprintf(text[NodeNAlreadyInPChat],n);
  113.     return; }
  114. if((node.action!=NODE_PAGE || node.aux!=node_num)
  115.     && node.misc&NODE_POFF && !SYSOP) {
  116.     bprintf(text[CantPageNode],node.misc&NODE_ANON
  117.         ? text[UNKNOWN_USER] : username(node.useron,tmp));
  118.     return; }
  119. if(node.action!=NODE_PAGE) {
  120.     bprintf("\r\n\1n\1mPaging \1h%s #%u\1n\1m for private chat\r\n"
  121.         ,node.misc&NODE_ANON ? text[UNKNOWN_USER] : username(node.useron,tmp)
  122.         ,node.useron);
  123.     sprintf(str,text[NodePChatPageMsg]
  124.         ,node_num,thisnode.misc&NODE_ANON
  125.             ? text[UNKNOWN_USER] : useron.alias);
  126.     putnmsg(n,str);
  127.     sprintf(str,"Paged %s on node %d to private chat"
  128.         ,username(node.useron,tmp),n);
  129.     logline("C",str); }
  130.  
  131. getnodedat(node_num,&thisnode,1);
  132. thisnode.action=action=NODE_PAGE;
  133. thisnode.aux=n;
  134. putnodedat(node_num,thisnode);
  135.  
  136. if(node.action!=NODE_PAGE || node.aux!=node_num) {
  137.     bprintf(text[WaitingForNodeInPChat],n);
  138.     while(online && !(sys_status&SS_ABORT)) {
  139.         getnodedat(n,&node,0);
  140.         if((node.action==NODE_PAGE || node.action==NODE_PCHT)
  141.             && node.aux==node_num) {
  142.             bprintf(text[NodeJoinedPrivateChat]
  143.                 ,n,node.misc&NODE_ANON ? text[UNKNOWN_USER]
  144.                     : username(node.useron,tmp));
  145.             break; }
  146.         if(!inkey(0))
  147.             mswait(1);
  148.         action=NODE_PAGE;
  149.         checkline();
  150.         gettimeleft();
  151.         SYNC; } }
  152.  
  153. getnodedat(node_num,&thisnode,1);
  154. thisnode.action=action=NODE_PCHT;
  155. putnodedat(node_num,thisnode);
  156.  
  157. if(!online || sys_status&SS_ABORT)
  158.     return;
  159.  
  160. if(useron.chat&CHAT_SPLITP && useron.misc&ANSI && rows>=24)
  161.     sys_status|=SS_SPLITP;
  162. /*
  163. if(!(useron.misc&EXPERT))
  164.     menu("PRIVCHAT");
  165. */
  166.  
  167. if(!(sys_status&SS_SPLITP))
  168.     bputs(text[WelcomeToPrivateChat]);
  169.  
  170. sprintf(str,"%sCHAT.DAB",node_dir);
  171. if((out=open(str,O_RDWR|O_DENYNONE|O_CREAT|O_BINARY
  172.     ,S_IREAD|S_IWRITE))==-1) {
  173.     errormsg(WHERE,ERR_OPEN,str,O_RDWR|O_DENYNONE|O_CREAT);
  174.     return; }
  175.  
  176. sprintf(str,"%sCHAT.DAB",node_path[n-1]);
  177. if(!fexist(str))        /* Wait while it's created for the first time */
  178.     mswait(2000);
  179. if((in=open(str,O_RDWR|O_DENYNONE|O_CREAT|O_BINARY
  180.     ,S_IREAD|S_IWRITE))==-1) {
  181.     close(out);
  182.     errormsg(WHERE,ERR_OPEN,str,O_RDWR|O_DENYNONE|O_CREAT);
  183.     return; }
  184.  
  185. if((p=(char *)MALLOC(PCHAT_LEN))==NULL) {
  186.     close(in);
  187.     close(out);
  188.     errormsg(WHERE,ERR_ALLOC,str,PCHAT_LEN);
  189.     return; }
  190. memset(p,0,PCHAT_LEN);
  191. write(in,p,PCHAT_LEN);
  192. write(out,p,PCHAT_LEN);
  193. FREE(p);
  194. lseek(in,0L,SEEK_SET);
  195. lseek(out,0L,SEEK_SET);
  196.  
  197. getnodedat(node_num,&thisnode,1);
  198. thisnode.misc&=~NODE_RPCHT;         /* Clear "reset pchat flag" */
  199. putnodedat(node_num,thisnode);
  200.  
  201. getnodedat(n,&node,1);
  202. node.misc|=NODE_RPCHT;                /* Set "reset pchat flag" */
  203. putnodedat(n,node);                 /* on other node */
  204.  
  205.                                     /* Wait for other node */
  206.                                     /* to acknowledge and reset */
  207. while(online && !(sys_status&SS_ABORT)) {
  208.     getnodedat(n,&node,0);
  209.     if(!(node.misc&NODE_RPCHT))
  210.         break;
  211.     getnodedat(node_num,&thisnode,0);
  212.     if(thisnode.misc&NODE_RPCHT)
  213.         break;
  214.     checkline();
  215.     gettimeleft();
  216.     SYNC;
  217.     inkey(0);
  218.     mswait(1); }
  219.  
  220.  
  221. action=NODE_PCHT;
  222. SYNC;
  223.  
  224. if(sys_status&SS_SPLITP) {
  225.     lncntr=0;
  226.     CLS;
  227.     ANSI_SAVE();
  228.     GOTOXY(1,13);
  229.     bprintf(sep
  230.         ,thisnode.misc&NODE_MSGW ? 'T':SP
  231.         ,sectostr(timeleft,tmp)
  232.         ,thisnode.misc&NODE_NMSG ? 'M':SP);
  233.     CRLF; }
  234.  
  235. done=0;
  236.  
  237. while(online && !(sys_status&SS_ABORT) && !done) {
  238.     RIOSYNC(0);
  239.     lncntr=0;
  240.     if(sys_status&SS_SPLITP)
  241.         lbuflen=0;
  242.     action=NODE_PCHT;
  243.     if(!localchar) {
  244.         if(sys_status&SS_SPLITP) {
  245.             getnodedat(node_num,&thisnode,0);
  246.             if(thisnode.misc&NODE_INTR)
  247.                 break;
  248.             if(thisnode.misc&NODE_UDAT && !(useron.rest&FLAG('G'))) {
  249.                 getuserdat(&useron);
  250.                 getnodedat(node_num,&thisnode,1);
  251.                 thisnode.misc&=~NODE_UDAT;
  252.                 putnodedat(node_num,thisnode); } }
  253.         else
  254.             nodesync(); }
  255.     activity=0;
  256.     if((ch=inkey(K_GETSTR))!=0) {
  257.         activity=1;
  258.         if(echo)
  259.             attr(color[clr_chatlocal]);
  260.         else
  261.             lclatr(color[clr_chatlocal]);
  262.         if(ch==BS) {
  263.             if(localchar) {
  264.                 if(echo)
  265.                     bputs("\b \b");
  266.                 else
  267.                     lputs("\b \b");
  268.                 localchar--;
  269.                 localbuf[localline][localchar]=0; } }
  270.         else if(ch==TAB) {
  271.             if(echo)
  272.                 outchar(SP);
  273.             else
  274.                 lputc(SP);
  275.             localbuf[localline][localchar]=SP;
  276.             localchar++;
  277.             while(localchar<78 && localchar%8) {
  278.                 if(echo)
  279.                     outchar(SP);
  280.                 else
  281.                     lputc(SP);
  282.                 localbuf[localline][localchar++]=SP; } }
  283.         else if(ch>=SP || ch==CR) {
  284.             if(ch!=CR) {
  285.                 if(echo)
  286.                     outchar(ch);
  287.                 else
  288.                     lputc(ch);
  289.                 localbuf[localline][localchar]=ch; }
  290.  
  291.             if(ch==CR || (localchar>68 && ch==SP) || ++localchar>78) {
  292.  
  293.                 localbuf[localline][localchar]=0;
  294.                 localchar=0;
  295.  
  296.                 if(sys_status&SS_SPLITP && lclwy()==24) {
  297.                     GOTOXY(1,13);
  298.                     bprintf(sep
  299.                         ,thisnode.misc&NODE_MSGW ? 'T':SP
  300.                         ,sectostr(timeleft,tmp)
  301.                         ,thisnode.misc&NODE_NMSG ? 'M':SP);
  302.                     attr(color[clr_chatlocal]);
  303.                     for(x=13,y=0;x<rows;x++,y++) {
  304.                         bprintf("\x1b[%d;1H\x1b[K",x+1);
  305.                         if(y<=localline)
  306.                             bprintf("%s\r\n",localbuf[y]); }
  307.                     GOTOXY(1,15+localline);
  308.                     localline=0; }
  309.                 else {
  310.                     if(localline>=4)
  311.                         for(i=0;i<4;i++)
  312.                             memcpy(localbuf[i],localbuf[i+1],81);
  313.                     else
  314.                         localline++;
  315.                     if(echo) {
  316.                         CRLF;
  317.                         if(sys_status&SS_SPLITP)
  318.                             bputs("\x1b[K"); }
  319.                     else
  320.                         lputs(crlf); }
  321.                 // SYNC;
  322.                 } }
  323.  
  324.         read(out,&c,1);
  325.         lseek(out,-1L,SEEK_CUR);
  326.         if(!c)        /* hasn't wrapped */
  327.             write(out,&ch,1);
  328.         else {
  329.             if(!tell(out))
  330.                 lseek(out,0L,SEEK_END);
  331.             lseek(out,-1L,SEEK_CUR);
  332.             ch=0;
  333.             write(out,&ch,1);
  334.             lseek(out,-1L,SEEK_CUR); }
  335.         if(tell(out)>=PCHAT_LEN)
  336.             lseek(out,0L,SEEK_SET);
  337.         }
  338.     else while(online) {
  339.         if(!(sys_status&SS_SPLITP))
  340.             remotechar=localchar;
  341.         if(tell(in)>=PCHAT_LEN)
  342.             lseek(in,0L,SEEK_SET);
  343.         ch=0;
  344.         read(in,&ch,1);
  345.         lseek(in,-1L,SEEK_CUR);
  346.         if(!ch) break;                      /* char from other node */
  347.         activity=1;
  348.         x=lclwx();
  349.         y=lclwy();
  350.         if(sys_status&SS_SPLITP)
  351.             ANSI_RESTORE();
  352.         attr(color[clr_chatremote]);
  353.         if(sys_status&SS_SPLITP)
  354.             bputs("\b \b");             /* Delete fake cursor */
  355.         if(ch==BS) {
  356.             if(remotechar) {
  357.                 bputs("\b \b");
  358.                 remotechar--;
  359.                 remotebuf[remoteline][remotechar]=0; } }
  360.         else if(ch==TAB) {
  361.             outchar(SP);
  362.             remotebuf[remoteline][remotechar]=SP;
  363.             remotechar++;
  364.             while(remotechar<78 && remotechar%8) {
  365.                 outchar(SP);
  366.                 remotebuf[remoteline][remotechar++]=SP; } }
  367.         else if(ch>=SP || ch==CR) {
  368.             if(ch!=CR) {
  369.                 outchar(ch);
  370.                 remotebuf[remoteline][remotechar]=ch; }
  371.  
  372.             if(ch==CR || (remotechar>68 && ch==SP) || ++remotechar>78) {
  373.  
  374.                 remotebuf[remoteline][remotechar]=0;
  375.                 remotechar=0;
  376.  
  377.                 if(sys_status&SS_SPLITP && lclwy()==12) {
  378.                     CRLF;
  379.                     bprintf(sep
  380.                         ,thisnode.misc&NODE_MSGW ? 'T':SP
  381.                         ,sectostr(timeleft,tmp)
  382.                         ,thisnode.misc&NODE_NMSG ? 'M':SP);
  383.                     attr(color[clr_chatremote]);
  384.                     for(i=0;i<12;i++) {
  385.                         bprintf("\x1b[%d;1H\x1b[K",i+1);
  386.                         if(i<=remoteline)
  387.                             bprintf("%s\r\n",remotebuf[i]); }
  388.                     remoteline=0;
  389.                     GOTOXY(1,6); }
  390.                 else {
  391.                     if(remoteline>=4)
  392.                         for(i=0;i<4;i++)
  393.                             memcpy(remotebuf[i],remotebuf[i+1],81);
  394.                     else
  395.                         remoteline++;
  396.                     if(echo) {
  397.                         CRLF;
  398.                         if(sys_status&SS_SPLITP)
  399.                             bputs("\x1b[K"); }
  400.                     else
  401.                         lputs(crlf); } } }
  402.         if(sys_status&SS_SPLITP) {
  403.             bputs("\1i_\1n");  /* Fake cursor */
  404.             ANSI_SAVE();
  405.             GOTOXY(x,y); }
  406.         ch=0;
  407.         write(in,&ch,1);
  408.  
  409.         if(!(sys_status&SS_SPLITP))
  410.             localchar=remotechar;
  411.         }
  412.     if(!activity) {                         /* no activity so chk node.dab */
  413.         getnodedat(n,&node,0);
  414.         if((node.action!=NODE_PCHT && node.action!=NODE_PAGE)
  415.             || node.aux!=node_num) {
  416.             bprintf(text[NodeLeftPrivateChat]
  417.                 ,n,node.misc&NODE_ANON ? text[UNKNOWN_USER]
  418.                 : username(node.useron,tmp));
  419.             break; }
  420.         getnodedat(node_num,&thisnode,0);
  421.         if(thisnode.misc&NODE_RPCHT) {        /* pchat has been reset */
  422.             lseek(in,0L,SEEK_SET);            /* so seek to beginning */
  423.             lseek(out,0L,SEEK_SET);
  424.             getnodedat(node_num,&thisnode,1);
  425.             thisnode.misc&=~NODE_RPCHT;
  426.             putnodedat(node_num,thisnode); }
  427.         mswait(0); }
  428.     checkline();
  429.     gettimeleft(); }
  430. if(sys_status&SS_SPLITP)
  431.     CLS;
  432. sys_status&=~SS_SPLITP;
  433. close(in);
  434. close(out);
  435. }
  436.  
  437. /****************************************************************************/
  438. /* The chat section                                                         */
  439. /****************************************************************************/
  440. void chatsection()
  441. {
  442.     uchar    line[256],str[256],ch,c,done,no_rip_menu
  443.             ,usrs,preusrs,qusrs,*gurubuf=NULL,channel,savch,*p
  444.             ,pgraph[400],buf[400]
  445.             ,usr[MAX_NODES],preusr[MAX_NODES],qusr[MAX_NODES];
  446.     int     file,in,out;
  447.     long    i,j,k,n;
  448.     node_t     node;
  449.  
  450. action=NODE_CHAT;
  451. if(useron.misc&(RIP|WIP) || !(useron.misc&EXPERT))
  452.     menu("CHAT");
  453. ASYNC;
  454. bputs(text[ChatPrompt]);
  455. while(online) {
  456.     no_rip_menu=0;
  457.     ch=getkeys("ACDJPQST?\r",0);
  458.     if(ch>SP)
  459.         logch(ch,0);
  460.     switch(ch) {
  461.         case 'S':
  462.             useron.chat^=CHAT_SPLITP;
  463.             putuserrec(useron.number,U_CHAT,8
  464.                 ,ltoa(useron.chat,str,16));
  465.             bprintf("\r\nPrivate split-screen chat is now: %s\r\n"
  466.                 ,useron.chat&CHAT_SPLITP ? text[ON]:text[OFF]);
  467.             break;
  468.         case 'A':
  469.             CRLF;
  470.             useron.chat^=CHAT_NOACT;
  471.             putuserrec(useron.number,U_CHAT,8
  472.                 ,ltoa(useron.chat,str,16));
  473.             getnodedat(node_num,&thisnode,1);
  474.             thisnode.misc^=NODE_AOFF;
  475.             printnodedat(node_num,thisnode);
  476.             putnodedat(node_num,thisnode);
  477.             no_rip_menu=1;
  478.             break;
  479.         case 'D':
  480.             CRLF;
  481.             useron.chat^=CHAT_NOPAGE;
  482.             putuserrec(useron.number,U_CHAT,8
  483.                 ,ltoa(useron.chat,str,16));
  484.             getnodedat(node_num,&thisnode,1);
  485.             thisnode.misc^=NODE_POFF;
  486.             printnodedat(node_num,thisnode);
  487.             putnodedat(node_num,thisnode);
  488.             no_rip_menu=1;
  489.             break;
  490.         case 'J':
  491.             if(!chan_access(0))
  492.                 break;
  493.             if(useron.misc&(RIP|WIP) ||!(useron.misc&EXPERT))
  494.                 menu("MULTCHAT");
  495.             getnodedat(node_num,&thisnode,1);
  496.             bputs(text[WelcomeToMultiChat]);
  497.             channel=thisnode.aux=1;        /* default channel 1 */
  498.             putnodedat(node_num,thisnode);
  499.             bprintf(text[WelcomeToChannelN],channel,chan[0]->name);
  500.             if(gurubuf) {
  501.                 FREE(gurubuf);
  502.                 gurubuf=NULL; }
  503.             if(chan[0]->misc&CHAN_GURU && chan[0]->guru<total_gurus
  504.                 && chk_ar(guru[chan[0]->guru]->ar,useron)) {
  505.                 sprintf(str,"%s%s.DAT",ctrl_dir,guru[chan[0]->guru]->code);
  506.                 if((file=nopen(str,O_RDONLY))==-1) {
  507.                     errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
  508.                     break; }
  509.                 if((gurubuf=MALLOC(filelength(file)+1))==NULL) {
  510.                     close(file);
  511.                     errormsg(WHERE,ERR_ALLOC,str,filelength(file)+1);
  512.                     break; }
  513.                 read(file,gurubuf,filelength(file));
  514.                 gurubuf[filelength(file)]=0;
  515.                 close(file); }
  516.             usrs=0;
  517.             for(i=1;i<=sys_nodes && i<=sys_lastnode;i++) {
  518.                 if(i==node_num)
  519.                     continue;
  520.                 getnodedat(i,&node,0);
  521.                 if(node.action!=NODE_MCHT || node.status!=NODE_INUSE)
  522.                     continue;
  523.                 if(node.aux && (node.aux&0xff)!=channel)
  524.                     continue;
  525.                 printnodedat(i,node);
  526.                 preusr[usrs]=usr[usrs++]=i; }
  527.             preusrs=usrs;
  528.             if(gurubuf)
  529.                 bprintf(text[NodeInMultiChatLocally]
  530.                     ,sys_nodes+1,guru[chan[channel-1]->guru]->name,channel);
  531.             bputs(text[YoureOnTheAir]);
  532.             done=0;
  533.             while(online && !done) {
  534.                 checkline();
  535.                 gettimeleft();
  536.                 action=NODE_MCHT;
  537.                 qusrs=usrs=0;
  538.                 for(i=1;i<=sys_nodes;i++) {
  539.                     if(i==node_num)
  540.                         continue;
  541.                     getnodedat(i,&node,0);
  542.                     if(node.action!=NODE_MCHT
  543.                         || (node.aux && channel && (node.aux&0xff)!=channel))
  544.                         continue;
  545.                     if(node.status==NODE_QUIET)
  546.                         qusr[qusrs++]=i;
  547.                     else if(node.status==NODE_INUSE)
  548.                         usr[usrs++]=i; }
  549.                 if(preusrs>usrs) {
  550.                     if(!usrs && channel && chan[channel-1]->misc&CHAN_GURU
  551.                         && chan[channel-1]->guru<total_gurus)
  552.                         bprintf(text[NodeJoinedMultiChat]
  553.                             ,sys_nodes+1,guru[chan[channel-1]->guru]->name
  554.                             ,channel);
  555.                     outchar(7);
  556.                     for(i=0;i<preusrs;i++) {
  557.                         for(j=0;j<usrs;j++)
  558.                             if(preusr[i]==usr[j])
  559.                                 break;
  560.                         if(j==usrs) {
  561.                             getnodedat(preusr[i],&node,0);
  562.                             if(node.misc&NODE_ANON)
  563.                                 sprintf(str,"%.80s",text[UNKNOWN_USER]);
  564.                             else
  565.                                 username(node.useron,str);
  566.                             bprintf(text[NodeLeftMultiChat]
  567.                                 ,preusr[i],str,channel); } } }
  568.                 else if(preusrs<usrs) {
  569.                     if(!preusrs && channel && chan[channel-1]->misc&CHAN_GURU
  570.                         && chan[channel-1]->guru<total_gurus)
  571.                         bprintf(text[NodeLeftMultiChat]
  572.                             ,sys_nodes+1,guru[chan[channel-1]->guru]->name
  573.                             ,channel);
  574.                     outchar(7);
  575.                     for(i=0;i<usrs;i++) {
  576.                         for(j=0;j<preusrs;j++)
  577.                             if(usr[i]==preusr[j])
  578.                                 break;
  579.                         if(j==preusrs) {
  580.                             getnodedat(usr[i],&node,0);
  581.                             if(node.misc&NODE_ANON)
  582.                                 sprintf(str,"%.80s",text[UNKNOWN_USER]);
  583.                             else
  584.                                 username(node.useron,str);
  585.                             bprintf(text[NodeJoinedMultiChat]
  586.                                 ,usr[i],str,channel); } } }
  587.                 preusrs=usrs;
  588.                 for(i=0;i<usrs;i++)
  589.                     preusr[i]=usr[i];
  590.                 attr(color[clr_multichat]);
  591.                 SYNC;
  592.                 sys_status&=~SS_ABORT;
  593.                 if((ch=inkey(0))!=0 || wordwrap[0]) {
  594.                     if(ch=='/') {
  595.                         bputs(text[MultiChatCommandPrompt]);
  596.                         strcpy(str,"ACELWQ?*");
  597.                         if(SYSOP)
  598.                             strcat(str,"0");
  599.                         i=getkeys(str,total_chans);
  600.                         if(i&0x80000000L) {  /* change channel */
  601.                             savch=i&~0x80000000L;
  602.                             if(savch==channel)
  603.                                 continue;
  604.                             if(!chan_access(savch-1))
  605.                                 continue;
  606.                             bprintf(text[WelcomeToChannelN]
  607.                                 ,savch,chan[savch-1]->name);
  608.  
  609.                             usrs=0;
  610.                             for(i=1;i<=sys_nodes;i++) {
  611.                                 if(i==node_num)
  612.                                     continue;
  613.                                 getnodedat(i,&node,0);
  614.                                 if(node.action!=NODE_MCHT
  615.                                     || node.status!=NODE_INUSE)
  616.                                     continue;
  617.                                 if(node.aux && (node.aux&0xff)!=savch)
  618.                                     continue;
  619.                                 printnodedat(i,node);
  620.                                 if(node.aux&0x1f00) {    /* password */
  621.                                     bprintf(text[PasswordProtected]
  622.                                         ,node.misc&NODE_ANON
  623.                                         ? text[UNKNOWN_USER]
  624.                                         : username(node.useron,tmp));
  625.                                     if(!getstr(str,8,K_UPPER|K_ALPHA|K_LINE))
  626.                                         break;
  627.                                     if(strcmp(str,unpackchatpass(tmp,node)))
  628.                                         break;
  629.                                         bputs(text[CorrectPassword]);  }
  630.                                 preusr[usrs]=usr[usrs++]=i; }
  631.                             if(i<=sys_nodes) {    /* failed password */
  632.                                 bputs(text[WrongPassword]);
  633.                                 continue; }
  634.                             if(gurubuf) {
  635.                                 FREE(gurubuf);
  636.                                 gurubuf=NULL; }
  637.                             if(chan[savch-1]->misc&CHAN_GURU
  638.                                 && chan[savch-1]->guru<total_gurus
  639.                                 && chk_ar(guru[chan[savch-1]->guru]->ar,useron
  640.                                 )) {
  641.                                 sprintf(str,"%s%s.DAT",ctrl_dir
  642.                                     ,guru[chan[savch-1]->guru]->code);
  643.                                 if((file=nopen(str,O_RDONLY))==-1) {
  644.                                     errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
  645.                                     break; }
  646.                                 if((gurubuf=MALLOC(filelength(file)+1))==NULL) {
  647.                                     close(file);
  648.                                     errormsg(WHERE,ERR_ALLOC,str
  649.                                         ,filelength(file)+1);
  650.                                     break; }
  651.                                 read(file,gurubuf,filelength(file));
  652.                                 gurubuf[filelength(file)]=0;
  653.                                 close(file); }
  654.                             preusrs=usrs;
  655.                             if(gurubuf)
  656.                                 bprintf(text[NodeInMultiChatLocally]
  657.                                     ,sys_nodes+1
  658.                                     ,guru[chan[savch-1]->guru]->name
  659.                                     ,savch);
  660.                             channel=savch;
  661.                             if(!usrs && chan[savch-1]->misc&CHAN_PW
  662.                                 && !noyes(text[PasswordProtectChanQ])) {
  663.                                 bputs(text[PasswordPrompt]);
  664.                                 if(getstr(str,8,K_UPPER|K_ALPHA|K_LINE)) {
  665.                                     getnodedat(node_num,&thisnode,1);
  666.                                     thisnode.aux=channel;
  667.                                     packchatpass(str,&thisnode); }
  668.                                 else {
  669.                                     getnodedat(node_num,&thisnode,1);
  670.                                     thisnode.aux=channel; } }
  671.                             else {
  672.                                 getnodedat(node_num,&thisnode,1);
  673.                                 thisnode.aux=channel; }
  674.                             putnodedat(node_num,thisnode);
  675.                             bputs(text[YoureOnTheAir]);
  676.                             if(chan[channel-1]->cost
  677.                                 && !(useron.exempt&FLAG('J')))
  678.                                 subtract_cdt(chan[channel-1]->cost); }
  679.                         else switch(i) {    /* other command */
  680.                             case '0':    /* Global channel */
  681.                                 if(!SYSOP)
  682.                                     break;
  683.                                 usrs=0;
  684.                                 for(i=1;i<=sys_nodes;i++) {
  685.                                     if(i==node_num)
  686.                                         continue;
  687.                                     getnodedat(i,&node,0);
  688.                                     if(node.action!=NODE_MCHT
  689.                                         || node.status!=NODE_INUSE)
  690.                                         continue;
  691.                                     printnodedat(i,node);
  692.                                     preusr[usrs]=usr[usrs++]=i; }
  693.                                 preusrs=usrs;
  694.                                 getnodedat(node_num,&thisnode,1);
  695.                                 thisnode.aux=channel=0;
  696.                                 putnodedat(node_num,thisnode);
  697.                                 break;
  698.                             case 'A':   /* Action commands */
  699.                                 useron.chat^=CHAT_ACTION;
  700.                                 bprintf("\r\nAction commands are now %s\r\n"
  701.                                     ,useron.chat&CHAT_ACTION
  702.                                     ? text[ON]:text[OFF]);
  703.                                 putuserrec(useron.number,U_CHAT,8
  704.                                     ,ltoa(useron.chat,str,16));
  705.                                 break;
  706.                             case 'C':   /* List of action commands */
  707.                                 CRLF;
  708.                                 for(i=0;i<total_chatacts;i++) {
  709.                                     if(chatact[i]->actset
  710.                                         !=chan[channel-1]->actset)
  711.                                         continue;
  712.                                     bprintf("%-*.*s",LEN_CHATACTCMD
  713.                                         ,LEN_CHATACTCMD,chatact[i]->cmd);
  714.                                     if(!((i+1)%8)) {
  715.                                         CRLF; }
  716.                                     else
  717.                                         bputs(" "); }
  718.                                 CRLF;
  719.                                 break;
  720.                             case 'E':   /* Toggle echo */
  721.                                 useron.chat^=CHAT_ECHO;
  722.                                 bprintf(text[EchoIsNow]
  723.                                     ,useron.chat&CHAT_ECHO
  724.                                     ? text[ON]:text[OFF]);
  725.                                 putuserrec(useron.number,U_CHAT,8
  726.                                     ,ltoa(useron.chat,str,16));
  727.                                 break;
  728.                             case 'L':    /* list nodes */
  729.                                 CRLF;
  730.                                 for(i=1;i<=sys_nodes && i<=sys_lastnode;i++) {
  731.                                     getnodedat(i,&node,0);
  732.                                     printnodedat(i,node); }
  733.                                 CRLF;
  734.                                 break;
  735.                             case 'W':   /* page node(s) */
  736.                                 j=getnodetopage(0,0);
  737.                                 if(!j)
  738.                                     break;
  739.                                 for(i=0;i<usrs;i++)
  740.                                     if(usr[i]==j)
  741.                                         break;
  742.                                 if(i>=usrs) {
  743.                                     bputs(text[UserNotFound]);
  744.                                     break; }
  745.  
  746.                                 bputs(text[NodeMsgPrompt]);
  747.                                 if(!getstr(line,66,K_LINE|K_MSG))
  748.                                     break;
  749.  
  750.                                 sprintf(buf,text[ChatLineFmt]
  751.                                     ,thisnode.misc&NODE_ANON
  752.                                     ? text[AnonUserChatHandle]
  753.                                     : useron.handle
  754.                                     ,node_num,'*',line);
  755.                                 strcat(buf,crlf);
  756.                                 if(useron.chat&CHAT_ECHO)
  757.                                     bputs(buf);
  758.                                 putnmsg(j,buf);
  759.                                 break;
  760.                             case 'Q':    /* quit */
  761.                                 done=1;
  762.                                 break;
  763.                             case '*':
  764.                                 sprintf(str,"%sMENU\\CHAN.*",text_dir);
  765.                                 if(fexist(str))
  766.                                     menu("CHAN");
  767.                                 else {
  768.                                     bputs(text[ChatChanLstHdr]);
  769.                                     bputs(text[ChatChanLstTitles]);
  770.                                     if(total_chans>=10) {
  771.                                         bputs("     ");
  772.                                         bputs(text[ChatChanLstTitles]); }
  773.                                     CRLF;
  774.                                     bputs(text[ChatChanLstUnderline]);
  775.                                     if(total_chans>=10) {
  776.                                         bputs("     ");
  777.                                         bputs(text[ChatChanLstUnderline]); }
  778.                                     CRLF;
  779.                                     if(total_chans>=10)
  780.                                         j=(total_chans/2)+(total_chans&1);
  781.                                     else
  782.                                         j=total_chans;
  783.                                     for(i=0;i<j && !msgabort();i++) {
  784.                                         bprintf(text[ChatChanLstFmt],i+1
  785.                                             ,chan[i]->name
  786.                                             ,chan[i]->cost);
  787.                                         if(total_chans>=10) {
  788.                                             k=(total_chans/2)
  789.                                                 +i+(total_chans&1);
  790.                                             if(k<total_chans) {
  791.                                                 bputs("     ");
  792.                                                 bprintf(text[ChatChanLstFmt]
  793.                                                     ,k+1
  794.                                                     ,chan[k]->name
  795.                                                     ,chan[k]->cost); } }
  796.                                         CRLF; }
  797.                                     CRLF; }
  798.                                 break;
  799.                             case '?':    /* menu */
  800.                                 menu("MULTCHAT");
  801.                                 break;    } }
  802.                     else {
  803.                         ungetkey(ch);
  804.                         j=0;
  805.                         pgraph[0]=0;
  806.                         while(j<5) {
  807.                             if(!getstr(line,66,K_WRAP|K_MSG|K_CHAT))
  808.                                 break;
  809.                             if(j) {
  810.                                 sprintf(str,text[ChatLineFmt]
  811.                                     ,thisnode.misc&NODE_ANON
  812.                                     ? text[AnonUserChatHandle]
  813.                                     : useron.handle
  814.                                     ,node_num,':',nulstr);
  815.                                 sprintf(tmp,"%*s",bstrlen(str),nulstr);
  816.                                 strcat(pgraph,tmp); }
  817.                             strcat(pgraph,line);
  818.                             strcat(pgraph,crlf);
  819.                             if(!wordwrap[0])
  820.                                 break;
  821.                             j++; }
  822.                         if(pgraph[0]) {
  823.                             if(useron.chat&CHAT_ACTION) {
  824.                                 for(i=0;i<total_chatacts;i++) {
  825.                                     if(chatact[i]->actset
  826.                                         !=chan[channel-1]->actset)
  827.                                         continue;
  828.                                     sprintf(str,"%s ",chatact[i]->cmd);
  829.                                     if(!strnicmp(str,pgraph,strlen(str)))
  830.                                         break;
  831.                                     sprintf(str,"%.*s"
  832.                                         ,LEN_CHATACTCMD+2,pgraph);
  833.                                     str[strlen(str)-2]=0;
  834.                                     if(!stricmp(chatact[i]->cmd,str))
  835.                                         break; }
  836.  
  837.                                 if(i<total_chatacts) {
  838.                                     p=pgraph+strlen(str);
  839.                                     n=atoi(p);
  840.                                     for(j=0;j<usrs;j++) {
  841.                                         getnodedat(usr[j],&node,0);
  842.                                         if(usrs==1) /* no need to search */
  843.                                             break;
  844.                                         if(n) {
  845.                                             if(usr[j]==n)
  846.                                                 break;
  847.                                             continue; }
  848.                                         username(node.useron,str);
  849.                                         if(!strnicmp(str,p,strlen(str)))
  850.                                             break;
  851.                                         getuserrec(node.useron,U_HANDLE
  852.                                             ,LEN_HANDLE,str);
  853.                                         if(!strnicmp(str,p,strlen(str)))
  854.                                             break; }
  855.                                     if(!usrs
  856.                                         && chan[channel-1]->guru<total_gurus)
  857.                                         strcpy(str
  858.                                         ,guru[chan[channel-1]->guru]->name);
  859.                                     else if(j>=usrs)
  860.                                         strcpy(str,"everyone");
  861.                                     else if(node.misc&NODE_ANON)
  862.                                         strcpy(str,text[UNKNOWN_USER]);
  863.                                     else
  864.                                         username(node.useron,str);
  865.  
  866.                                     /* Display on same node */
  867.                                     bprintf(chatact[i]->out
  868.                                         ,thisnode.misc&NODE_ANON
  869.                                         ? text[UNKNOWN_USER] : useron.alias
  870.                                         ,str);
  871.                                     CRLF;
  872.  
  873.                                     if(usrs && j<usrs) {
  874.                                         /* Display to dest user */
  875.                                         sprintf(buf,chatact[i]->out
  876.                                             ,thisnode.misc&NODE_ANON
  877.                                             ? text[UNKNOWN_USER] : useron.alias
  878.                                             ,"you");
  879.                                         strcat(buf,crlf);
  880.                                         putnmsg(usr[j],buf); }
  881.  
  882.  
  883.                                     /* Display to all other users */
  884.                                     sprintf(buf,chatact[i]->out
  885.                                         ,thisnode.misc&NODE_ANON
  886.                                         ? text[UNKNOWN_USER] : useron.alias
  887.                                         ,str);
  888.                                     strcat(buf,crlf);
  889.  
  890.                                     for(i=0;i<usrs;i++) {
  891.                                         if(i==j)
  892.                                             continue;
  893.                                         getnodedat(usr[i],&node,0);
  894.                                         putnmsg(usr[i],buf); }
  895.                                     for(i=0;i<qusrs;i++) {
  896.                                         getnodedat(qusr[i],&node,0);
  897.                                         putnmsg(qusr[i],buf); }
  898.                                     continue; } }
  899.  
  900.                             sprintf(buf,text[ChatLineFmt]
  901.                                 ,thisnode.misc&NODE_ANON
  902.                                 ? text[AnonUserChatHandle]
  903.                                 : useron.handle
  904.                                 ,node_num,':',pgraph);
  905.                             if(useron.chat&CHAT_ECHO)
  906.                                 bputs(buf);
  907.                             for(i=0;i<usrs;i++) {
  908.                                 getnodedat(usr[i],&node,0);
  909.                                 putnmsg(usr[i],buf); }
  910.                             for(i=0;i<qusrs;i++) {
  911.                                 getnodedat(qusr[i],&node,0);
  912.                                 putnmsg(qusr[i],buf); }
  913.                             if(!usrs && channel && gurubuf
  914.                                 && chan[channel-1]->misc&CHAN_GURU)
  915.                                 guruchat(pgraph,gurubuf,chan[channel-1]->guru);
  916.                                 } } }
  917.                 else
  918.                     mswait(1);
  919.                 if(sys_status&SS_ABORT)
  920.                     break; }
  921.             lncntr=0;
  922.             break;
  923.         case 'P':   /* private node-to-node chat */
  924.             privchat();
  925.             break;
  926.         case 'C':
  927.             no_rip_menu=1;
  928.             ch=kbd_state();      /* Check scroll lock */
  929.             if(ch&16 || (sys_chat_ar[0] && chk_ar(sys_chat_ar,useron))
  930.                 || useron.exempt&FLAG('C')) {
  931.                 sysop_page();
  932.                 break; }
  933.             bprintf(text[SysopIsNotAvailable],sys_op);
  934.             if(total_gurus && chk_ar(guru[0]->ar,useron)) {
  935.                 sprintf(str,text[ChatWithGuruInsteadQ],guru[0]->name);
  936.                 if(!yesno(str))
  937.                     break; }
  938.             else
  939.                 break;
  940.         case 'T':
  941.             if(!total_gurus) {
  942.                 bprintf(text[SysopIsNotAvailable],"The Guru");
  943.                 break; }
  944.             if(total_gurus==1 && chk_ar(guru[0]->ar,useron))
  945.                 i=0;
  946.             else {
  947.                 for(i=0;i<total_gurus;i++)
  948.                     uselect(1,i,nulstr,guru[i]->name,guru[i]->ar);
  949.                 i=uselect(0,0,0,0,0);
  950.                 if(i<0)
  951.                     break; }
  952.             if(gurubuf)
  953.                 FREE(gurubuf);
  954.             sprintf(str,"%s%s.DAT",ctrl_dir,guru[i]->code);
  955.             if((file=nopen(str,O_RDONLY))==-1) {
  956.                 errormsg(WHERE,ERR_OPEN,str,O_RDONLY);
  957.                 return; }
  958.             if((gurubuf=MALLOC(filelength(file)+1))==NULL) {
  959.                 close(file);
  960.                 errormsg(WHERE,ERR_ALLOC,str,filelength(file)+1);
  961.                 return; }
  962.             read(file,gurubuf,filelength(file));
  963.             gurubuf[filelength(file)]=0;
  964.             close(file);
  965.             localguru(gurubuf,i);
  966.             no_rip_menu=1;
  967.             FREE(gurubuf);
  968.             gurubuf=NULL;
  969.             break;
  970.         case '?':
  971.             if(useron.misc&EXPERT)
  972.                 menu("CHAT");
  973.             break;
  974.         default:    /* 'Q' or <CR> */
  975.             lncntr=0;
  976.             if(gurubuf)
  977.                 FREE(gurubuf);
  978.             return; }
  979.     action=NODE_CHAT;
  980.     if(!(useron.misc&EXPERT) || useron.misc&WIP
  981.         || (useron.misc&RIP && !no_rip_menu)) {
  982. #if 0
  983.         sys_status&=~SS_ABORT;
  984.         if(lncntr) {
  985.             SYNC;
  986.             CRLF;
  987.             if(lncntr)            /* CRLF or SYNC can cause pause */
  988.                 pause(); }
  989. #endif
  990.         menu("CHAT"); }
  991.     ASYNC;
  992.     bputs(text[ChatPrompt]); }
  993. if(gurubuf)
  994.     FREE(gurubuf);
  995. }
  996.  
  997. int getnodetopage(int all, int telegram)
  998. {
  999.     static    uchar last[26];
  1000.     char    str[128];
  1001.     int     i,j;
  1002.     ulong    l;
  1003.     node_t    node;
  1004.  
  1005. if(!lastnodemsg)
  1006.     last[0]=0;
  1007. if(lastnodemsg) {
  1008.     getnodedat(lastnodemsg,&node,0);
  1009.     if(node.status!=NODE_INUSE && !SYSOP)
  1010.         lastnodemsg=1; }
  1011. for(j=0,i=1;i<=sys_nodes && i<=sys_lastnode;i++) {
  1012.     getnodedat(i,&node,0);
  1013.     if(i==node_num)
  1014.         continue;
  1015.     if(node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET)) {
  1016.         if(!lastnodemsg)
  1017.             lastnodemsg=i;
  1018.         j++; } }
  1019.  
  1020. if(!last[0])
  1021.     sprintf(last,"%u",lastnodemsg);
  1022.  
  1023. if(!j && !telegram) {
  1024.     bputs(text[NoOtherActiveNodes]);
  1025.     return(0); }
  1026.  
  1027. if(all)
  1028.     sprintf(str,text[NodeToSendMsgTo],lastnodemsg);
  1029. else
  1030.     sprintf(str,text[NodeToPrivateChat],lastnodemsg);
  1031. mnemonics(str);
  1032.  
  1033. strcpy(str,last);
  1034. getstr(str,25,K_UPRLWR|K_LINE|K_EDIT|K_AUTODEL);
  1035. if(sys_status&SS_ABORT)
  1036.     return(0);
  1037. if(!str[0])
  1038.     return(0);
  1039.  
  1040. j=atoi(str);
  1041. if(j && j<=sys_lastnode && j<=sys_nodes) {
  1042.     getnodedat(j,&node,0);
  1043.     if(node.status!=NODE_INUSE && !SYSOP) {
  1044.         bprintf(text[NodeNIsNotInUse],j);
  1045.         return(0); }
  1046.     if(telegram && node.misc&(NODE_POFF|NODE_ANON) && !SYSOP) {
  1047.         bprintf(text[CantPageNode],node.misc&NODE_ANON
  1048.             ? text[UNKNOWN_USER] : username(node.useron,tmp));
  1049.         return(0); }
  1050.     strcpy(last,str);
  1051.     if(telegram)
  1052.         return(node.useron);
  1053.     return(j); }
  1054. if(all && !stricmp(str,"ALL"))
  1055.     return(-1);
  1056.  
  1057. if(str[0]=='\'') {
  1058.     j=userdatdupe(0,U_HANDLE,LEN_HANDLE,str+1,0);
  1059.     if(!j) {
  1060.         bputs(text[UnknownUser]);
  1061.         return(0); } }
  1062. else if(str[0]=='#')
  1063.     j=atoi(str+1);
  1064. else
  1065.     j=finduser(str);
  1066. if(!j)
  1067.     return(0);
  1068. if(j>lastuser())
  1069.     return(0);
  1070. getuserrec(j,U_MISC,8,tmp);
  1071. l=ahtoul(tmp);
  1072. if(l&(DELETED|INACTIVE)) {              /* Deleted or Inactive User */
  1073.     bputs(text[UnknownUser]);
  1074.     return(0); }
  1075.  
  1076. for(i=1;i<=sys_nodes && i<=sys_lastnode;i++) {
  1077.     getnodedat(i,&node,0);
  1078.     if((node.status==NODE_INUSE || (SYSOP && node.status==NODE_QUIET))
  1079.         && node.useron==j) {
  1080.         if(telegram && node.misc&NODE_POFF && !SYSOP) {
  1081.             bprintf(text[CantPageNode],node.misc&NODE_ANON
  1082.                 ? text[UNKNOWN_USER] : username(node.useron,tmp));
  1083.             return(0); }
  1084.         if(telegram)
  1085.             return(j);
  1086.         strcpy(last,str);
  1087.         return(i); } }
  1088. if(telegram) {
  1089.     strcpy(last,str);
  1090.     return(j); }
  1091. bputs(text[UserNotFound]);
  1092. return(0);
  1093. }
  1094.  
  1095.  
  1096. /****************************************************************************/
  1097. /* Sending single line messages between nodes                               */
  1098. /****************************************************************************/
  1099. void nodemsg()
  1100. {
  1101.     static    inside;
  1102.     char    str[256],line[256],buf[512],ch;
  1103.     int     i,j,usernumber,done=0;
  1104.     node_t    node,savenode;
  1105.  
  1106. if(inside>1)    /* nested once only */
  1107.     return;
  1108. sys_status|=SS_IN_CTRLP;
  1109. getnodedat(node_num,&savenode,0);
  1110. inside++;
  1111. wordwrap[0]=0;
  1112. while(online && !done) {
  1113.     if(useron.rest&FLAG('C')) {
  1114.         bputs(text[R_SendMessages]);
  1115.         break; }
  1116.     SYNC;
  1117.     mnemonics(text[PrivateMsgPrompt]);
  1118.     sys_status&=~SS_ABORT;
  1119.     while(online) {      /* Watch for incoming messages */
  1120.         ch=toupper(inkey(0));
  1121.         if(ch && strchr("TMCQ\r",ch))
  1122.             break;
  1123.         if(sys_status&SS_ABORT)
  1124.             break;
  1125.         if(online==ON_REMOTE && rioctl(IOSTATE)&ABORT) {
  1126.             sys_status|=SS_ABORT;
  1127.             break; }
  1128.         getnodedat(node_num,&thisnode,0);
  1129.         if(thisnode.misc&(NODE_MSGW|NODE_NMSG)) {
  1130.             SAVELINE;
  1131.             CRLF;
  1132.             if(thisnode.misc&NODE_NMSG)
  1133.                 getnmsg();
  1134.             if(thisnode.misc&NODE_MSGW)
  1135.                 getsmsg(useron.number);
  1136.             CRLF;
  1137.             RESTORELINE; }
  1138.         else
  1139.             nodesync();
  1140.         gettimeleft();
  1141.         checkline(); }
  1142.  
  1143.     if(!online || sys_status&SS_ABORT) {
  1144.         sys_status&=~SS_ABORT;
  1145.         CRLF;
  1146.         break; }
  1147.  
  1148.     switch(toupper(ch)) {
  1149.         case 'T':   /* Telegram */
  1150.             bputs("Telegram\r\n");
  1151.             usernumber=getnodetopage(0,1);
  1152.             if(!usernumber)
  1153.                 break;
  1154.  
  1155.             if(usernumber==1 && useron.rest&FLAG('S')) { /* ! val fback */
  1156.                 bprintf(text[R_Feedback],sys_op);
  1157.                 break; }
  1158.             if(usernumber!=1 && useron.rest&FLAG('E')) {
  1159.                 bputs(text[R_Email]);
  1160.                 break; }
  1161.             now=time(NULL);
  1162.             bprintf("\1n\r\n\1mSending telegram to \1h%s #%u\1n\1m (Max 5 "
  1163.                 "lines, Blank line ends):\r\n\r\n\1g\1h"
  1164.                 ,username(usernumber,tmp),usernumber);
  1165.             sprintf(buf,"\1n\1g\7Telegram from \1n\1h%s\1n\1g on %s:\r\n\1h"
  1166.                 ,thisnode.misc&NODE_ANON ? text[UNKNOWN_USER] : useron.alias
  1167.                 ,timestr(&now));
  1168.             i=0;
  1169.             while(online && i<5) {
  1170.                 bprintf("%4s",nulstr);
  1171.                 if(!getstr(line,70,K_WRAP|K_MSG))
  1172.                     break;
  1173.                 sprintf(str,"%4s%s\r\n",nulstr,line);
  1174.                 strcat(buf,str);
  1175.                 i++; }
  1176.             if(!i)
  1177.                 break;
  1178.             if(sys_status&SS_ABORT) {
  1179.                 CRLF;
  1180.                 break; }
  1181.             putsmsg(usernumber,buf);
  1182.             sprintf(str,"Sent telegram to %s #%u"
  1183.                 ,username(usernumber,tmp),usernumber);
  1184.             logline("C",str);
  1185.             logline(nulstr,line);
  1186.             bprintf("\1n\1mTelegram sent to \1h%s\r\n"
  1187.                 ,username(usernumber,tmp));
  1188.             break;
  1189.         case 'M':   /* Message */
  1190.             bputs("Message\r\n");
  1191.             i=getnodetopage(1,0);
  1192.             if(!i)
  1193.                 break;
  1194.             if(i!=-1) {
  1195.                 getnodedat(i,&node,0);
  1196.                 usernumber=node.useron;
  1197.                 if(node.misc&NODE_POFF && !SYSOP)
  1198.                     bprintf(text[CantPageNode],node.misc&NODE_ANON
  1199.                         ? text[UNKNOWN_USER] : username(node.useron,tmp));
  1200.                 else {
  1201.                     bprintf("\r\n\1n\1mSending message to \1h%s\r\n"
  1202.                         ,node.misc&NODE_ANON ? text[UNKNOWN_USER]
  1203.                         : username(node.useron,tmp));
  1204.                     bputs(text[NodeMsgPrompt]);
  1205.                     if(!getstr(line,69,K_LINE))
  1206.                         break;
  1207.                     sprintf(buf,text[NodeMsgFmt],node_num
  1208.                         ,thisnode.misc&NODE_ANON
  1209.                             ? text[UNKNOWN_USER] : useron.alias,line);
  1210.                     putnmsg(i,buf);
  1211.                     if(!(node.misc&NODE_ANON))
  1212.                         bprintf("\r\n\1n\1mMessage sent to \1h%s #%u\r\n"
  1213.                             ,username(usernumber,tmp),usernumber);
  1214.                     sprintf(str,"Sent message to %s on node %d:"
  1215.                         ,username(usernumber,tmp),i);
  1216.                     logline("C",str);
  1217.                     logline(nulstr,line); } }
  1218.             else {    /* ALL */
  1219.                 bputs(text[NodeMsgPrompt]);
  1220.                 if(!getstr(line,70,K_LINE))
  1221.                     break;
  1222.                 sprintf(buf,text[AllNodeMsgFmt],node_num
  1223.                     ,thisnode.misc&NODE_ANON
  1224.                         ? text[UNKNOWN_USER] : useron.alias,line);
  1225.                 for(i=1;i<=sys_nodes;i++) {
  1226.                     if(i==node_num)
  1227.                         continue;
  1228.                     getnodedat(i,&node,0);
  1229.                     if((node.status==NODE_INUSE
  1230.                         || (SYSOP && node.status==NODE_QUIET))
  1231.                         && (SYSOP || !(node.misc&NODE_POFF)))
  1232.                         putnmsg(i,buf); }
  1233.                 logline("C","Sent message to all nodes");
  1234.                 logline(nulstr,line); }
  1235.             break;
  1236.         case 'C':   /* Chat */
  1237.             bputs("Chat\r\n");
  1238.             if(action==NODE_PCHT) { /* already in pchat */
  1239.                 done=1;
  1240.                 break; }
  1241.             privchat();
  1242.             action=savenode.action;
  1243.             break;
  1244.         default:
  1245.             bputs("Quit\r\n");
  1246.             done=1;
  1247.             break; } }
  1248. inside--;
  1249. if(!inside)
  1250.     sys_status&=~SS_IN_CTRLP;
  1251. getnodedat(node_num,&thisnode,1);
  1252. thisnode.action=action=savenode.action;
  1253. thisnode.aux=savenode.aux;
  1254. thisnode.extaux=savenode.extaux;
  1255. putnodedat(node_num,thisnode);
  1256. }
  1257.  
  1258. /****************************************************************************/
  1259. /* The guru will respond from the 'guru' buffer to 'line'                   */
  1260. /****************************************************************************/
  1261. void guruchat(char *line, char *gurubuf, int gurunum)
  1262. {
  1263.     char    str[256],cstr[256],*ptr,c,*answer[100],answers,theanswer[769]
  1264.             ,mistakes=1,hu=0;
  1265.     int     i,j,k,file;
  1266.     long     len;
  1267.     struct    tm *tm;
  1268.  
  1269. now=time(NULL);
  1270. tm=localtime(&now);
  1271.  
  1272. for(i=0;i<100;i++) {
  1273.     if((answer[i]=MALLOC(513))==NULL) {
  1274.         errormsg(WHERE,ERR_ALLOC,nulstr,513);
  1275.         while(i) {
  1276.             i--;
  1277.             FREE(answer[i]); }
  1278.         sys_status&=~SS_GURUCHAT;
  1279.         return; } }
  1280. ptr=gurubuf;
  1281. len=strlen(gurubuf);
  1282. strupr(line);
  1283. j=strlen(line);
  1284. k=0;
  1285. for(i=0;i<j;i++) {
  1286.     if(!isalnum(line[i]) && !k)    /* beginning non-alphanumeric */
  1287.         continue;
  1288.     if(!isalnum(line[i]) && line[i]==line[i+1])    /* redundant non-alnum */
  1289.         continue;
  1290.     if(!isalnum(line[i]) && line[i+1]=='?')    /* fix "WHAT ?" */
  1291.         continue;
  1292.     cstr[k++]=line[i]; }
  1293. cstr[k]=0;
  1294. while(--k) {
  1295.     if(!isalnum(cstr[k]))
  1296.         continue;
  1297.     break; }
  1298. if(k<1) {
  1299.     for(i=0;i<100;i++)
  1300.         FREE(answer[i]);
  1301.     return; }
  1302. if(cstr[k+1]=='?')
  1303.     k++;
  1304. cstr[k+1]=0;
  1305. while(*ptr && ptr<gurubuf+len) {
  1306.     if(*ptr=='(') {
  1307.         ptr++;
  1308.         if(!guruexp(&ptr,cstr)) {
  1309.             while(*ptr && *ptr!='(' && ptr<gurubuf+len)
  1310.                 ptr++;
  1311.             continue; } }
  1312.     else {
  1313.         while(*ptr && *ptr!=LF && ptr<gurubuf+len) /* skip LF after ')' */
  1314.             ptr++;
  1315.         ptr++;
  1316.         answers=0;
  1317.         while(*ptr && answers<100 && ptr<gurubuf+len) {
  1318.             i=0;
  1319.             while(*ptr && *ptr!=CR && i<512 && ptr<gurubuf+len) {
  1320.                 answer[answers][i]=*ptr;
  1321.                 ptr++;
  1322.                 i++;
  1323.                 if(*ptr=='\\' && *(ptr+1)==CR) {    /* multi-line answer */
  1324.                     ptr+=3;    /* skip \CRLF */
  1325.                     answer[answers][i++]=CR;
  1326.                     answer[answers][i++]=LF; } }
  1327.             answer[answers][i]=0;
  1328.             if(!strlen(answer[answers]) || answer[answers][0]=='(') {
  1329.                 ptr-=strlen(answer[answers]);
  1330.                 break; }
  1331.             ptr+=2;    /* skip CRLF */
  1332.             answers++; }
  1333.         if(answers==100)
  1334.             while(*ptr && *ptr!='(' && ptr<gurubuf+len)
  1335.                 ptr++;
  1336.         i=random(answers);
  1337.         for(j=0,k=0;j<strlen(answer[i]);j++) {
  1338.             if(answer[i][j]=='`') {
  1339.                 j++;
  1340.                 theanswer[k]=0;
  1341.                 switch(toupper(answer[i][j])) {
  1342.                     case 'A':
  1343.                         if(sys_status&SS_USERON)
  1344.                             strcat(theanswer,useron.alias);
  1345.                         else
  1346.                             strcat(theanswer,text[UNKNOWN_USER]);
  1347.                         break;
  1348.                     case 'B':
  1349.                         if(sys_status&SS_USERON)
  1350.                             strcat(theanswer,useron.birth);
  1351.                         else
  1352.                             strcat(theanswer,"00/00/00");
  1353.                         break;
  1354.                     case 'C':
  1355.                         if(sys_status&SS_USERON)
  1356.                             strcat(theanswer,useron.comp);
  1357.                         else
  1358.                             strcat(theanswer,"PC Jr.");
  1359.                         break;
  1360.                     case 'D':
  1361.                         if(sys_status&SS_USERON)
  1362.                             strcat(theanswer,ultoac(useron.dlb,tmp));
  1363.                         else
  1364.                             strcat(theanswer,"0");
  1365.                         break;
  1366.                     case 'G':
  1367.                         strcat(theanswer,guru[gurunum]->name);
  1368.                         break;
  1369.                     case 'H':
  1370.                         hu=1;
  1371.                         break;
  1372.                     case 'I':
  1373.                         strcat(theanswer,sys_id);
  1374.                         break;
  1375.                     case 'J':
  1376.                         sprintf(tmp,"%u",tm->tm_mday);
  1377.                         break;
  1378.                     case 'L':
  1379.                         if(sys_status&SS_USERON)
  1380.                             strcat(theanswer,itoa(useron.level,tmp,10));
  1381.                         else
  1382.                             strcat(theanswer,"0");
  1383.                         break;
  1384.                     case 'M':
  1385.                         strcat(theanswer,month[tm->tm_mon]);
  1386.                         break;
  1387.                     case 'N':   /* Note */
  1388.                         if(sys_status&SS_USERON)
  1389.                             strcat(theanswer,useron.note);
  1390.                         else
  1391.                             strcat(theanswer,text[UNKNOWN_USER]);
  1392.                         break;
  1393.                     case 'O':
  1394.                         strcat(theanswer,sys_op);
  1395.                         break;
  1396.                     case 'P':
  1397.                         if(sys_status&SS_USERON)
  1398.                             strcat(theanswer,useron.phone);
  1399.                         else
  1400.                             strcat(theanswer,"000-000-0000");
  1401.                         break;
  1402.                     case 'Q':
  1403.                             sys_status&=~SS_GURUCHAT;
  1404.                         break;
  1405.                     case 'R':
  1406.                         if(sys_status&SS_USERON)
  1407.                             strcat(theanswer,useron.name);
  1408.                         else
  1409.                             strcat(theanswer,text[UNKNOWN_USER]);
  1410.                         break;
  1411.                     case 'S':
  1412.                         strcat(theanswer,sys_name);
  1413.                         break;
  1414.                     case 'T':
  1415.                         sprintf(tmp,"%u:%02u",tm->tm_hour>12 ? tm->tm_hour-12
  1416.                             : tm->tm_hour,tm->tm_min);
  1417.                         strcat(theanswer,tmp);
  1418.                         break;
  1419.                     case 'U':
  1420.                         if(sys_status&SS_USERON)
  1421.                             strcat(theanswer,ultoac(useron.ulb,tmp));
  1422.                         else
  1423.                             strcat(theanswer,"0");
  1424.                         break;
  1425.                     case 'W':
  1426.                         strcat(theanswer,weekday[tm->tm_wday]);
  1427.                         break;
  1428.                     case 'Y':   /* Current year */
  1429.                         sprintf(tmp,"%u",1900+tm->tm_year);
  1430.                         strcat(theanswer,tmp);
  1431.                         break;
  1432.                     case 'Z':
  1433.                         if(sys_status&SS_USERON)
  1434.                             strcat(theanswer,useron.zipcode);
  1435.                         else
  1436.                             strcat(theanswer,"90210");
  1437.                         break;
  1438.                     case '$':   /* Credits */
  1439.                         if(sys_status&SS_USERON)
  1440.                             strcat(theanswer,ultoac(useron.cdt,tmp));
  1441.                         else
  1442.                             strcat(theanswer,"0");
  1443.                         break;
  1444.                     case '#':
  1445.                         if(sys_status&SS_USERON)
  1446.                             strcat(theanswer,itoa(getage(useron.birth)
  1447.                                 ,tmp,10));
  1448.                         else
  1449.                             strcat(theanswer,"0");
  1450.                         break;
  1451.                     case '!':
  1452.                         mistakes=!mistakes;
  1453.                         break;
  1454.                     case '_':
  1455.                         mswait(500);
  1456.                         break; }
  1457.                 k=strlen(theanswer); }
  1458.             else
  1459.                 theanswer[k++]=answer[i][j]; }
  1460.         theanswer[k]=0;
  1461.         mswait(500+random(1000));     /* thinking time */
  1462.         if(action!=NODE_MCHT) {
  1463.             for(i=0;i<k;i++) {
  1464.                 if(mistakes && theanswer[i]!=theanswer[i-1] &&
  1465.                     ((!isalnum(theanswer[i]) && !random(100))
  1466.                     || (isalnum(theanswer[i]) && !random(30)))) {
  1467.                     c=j=random(3)+1;    /* 1 to 3 chars */
  1468.                     if(c<strcspn(theanswer+(i+1),"\0., "))
  1469.                         c=j=1;
  1470.                     while(j) {
  1471.                         outchar(97+random(26));
  1472.                         mswait(25+random(150));
  1473.                         j--; }
  1474.                     if(random(100)) {
  1475.                         mswait(100+random(300));
  1476.                         while(c) {
  1477.                             bputs("\b \b");
  1478.                             mswait(50+random(50));
  1479.                             c--; } } }
  1480.                 outchar(theanswer[i]);
  1481.                 if(theanswer[i]==theanswer[i+1])
  1482.                     mswait(25+random(50));
  1483.                 else
  1484.                     mswait(25+random(150));
  1485.                 if(theanswer[i]==SP)
  1486.                     mswait(random(50)); } }
  1487.         else {
  1488.             mswait(strlen(theanswer)*100);
  1489.             bprintf(text[ChatLineFmt],guru[gurunum]->name
  1490.                 ,sys_nodes+1,':',theanswer); }
  1491.         CRLF;
  1492.         sprintf(str,"%sGURU.LOG",data_dir);
  1493.         if((file=nopen(str,O_WRONLY|O_CREAT|O_APPEND))==-1)
  1494.             errormsg(WHERE,ERR_OPEN,str,O_WRONLY|O_CREAT|O_APPEND);
  1495.         else {
  1496.             if(action==NODE_MCHT) {
  1497.                 sprintf(str,"[Multi] ");
  1498.                 write(file,str,strlen(str)); }
  1499.             sprintf(str,"%s:\r\n",sys_status&SS_USERON
  1500.                 ? useron.alias : "UNKNOWN");
  1501.             write(file,str,strlen(str));
  1502.             write(file,line,strlen(line));
  1503.             if(action!=NODE_MCHT)
  1504.                 write(file,crlf,2);
  1505.             sprintf(str,"%s:\r\n",guru[gurunum]->name);
  1506.             write(file,str,strlen(str));
  1507.             write(file,theanswer,strlen(theanswer));
  1508.             write(file,crlf,2);
  1509.             close(file); }
  1510.         if(hu)
  1511.             hangup();
  1512.         break; } }
  1513. for(i=0;i<100;i++)
  1514.     FREE(answer[i]);
  1515. }
  1516.  
  1517. /****************************************************************************/
  1518. /* An expression from the guru's buffer 'ptrptr' is evaluated and true or   */
  1519. /* false is returned.                                                       */
  1520. /****************************************************************************/
  1521. char guruexp(char **ptrptr, char *line)
  1522. {
  1523.     char    c,*cp,str[256],true=0,and=0,or=0,nest,*ar;
  1524.  
  1525. if((**ptrptr)==')') {    /* expressions of () are always true */
  1526.     (*ptrptr)++;
  1527.     return(1); }
  1528. while((**ptrptr)!=')' && (**ptrptr)) {
  1529.     if((**ptrptr)=='[') {
  1530.         (*ptrptr)++;
  1531.         sprintf(str,"%.128s",*ptrptr);
  1532.         while(**ptrptr && (**ptrptr)!=']')
  1533.             (*ptrptr)++;
  1534.         (*ptrptr)++;
  1535.         cp=strchr(str,']');
  1536.         if(cp) *cp=0;
  1537.         ar=arstr(NULL,str);
  1538.         c=chk_ar(ar,useron);
  1539.         if(ar[0]!=AR_NULL)
  1540.             FREE(ar);
  1541.         if(!c && and) {
  1542.             true=0;
  1543.             break; }
  1544.         if(c && or) {
  1545.             true=1;
  1546.             break; }
  1547.         if(c)
  1548.             true=1;
  1549.         continue; }
  1550.     if((**ptrptr)=='(') {
  1551.         (*ptrptr)++;
  1552.         c=guruexp(&(*ptrptr),line);
  1553.         if(!c && and) {
  1554.             true=0;
  1555.             break; }
  1556.         if(c && or) {
  1557.             true=1;
  1558.             break; }
  1559.         if(c)
  1560.             true=1;    }
  1561.     if((**ptrptr)==')')
  1562.         break;
  1563.     c=0;
  1564.     while((**ptrptr) && isspace(**ptrptr))
  1565.         (*ptrptr)++;
  1566.     while((**ptrptr)!='|' && (**ptrptr)!='&' && (**ptrptr)!=')' &&(**ptrptr)) {
  1567.         str[c++]=(**ptrptr);
  1568.         (*ptrptr)++; }
  1569.     str[c]=0;
  1570.     if((**ptrptr)=='|') {
  1571.         if(!c && true)
  1572.             break;
  1573.         and=0;
  1574.         or=1; }
  1575.     else if((**ptrptr)=='&') {
  1576.         if(!c && !true)
  1577.             break;
  1578.         and=1;
  1579.         or=0; }
  1580.     if(!c) {                /* support ((exp)op(exp)) */
  1581.         (*ptrptr)++;
  1582.         continue; }
  1583.     if((**ptrptr)!=')')
  1584.         (*ptrptr)++;
  1585.     c=0;                    /* c now used for start line flag */
  1586.     if(str[strlen(str)-1]=='^') {    /* ^signifies start of line only */
  1587.         str[strlen(str)-1]=0;
  1588.         c=1; }
  1589.     if(str[strlen(str)-1]=='~') {    /* ~signifies non-isolated word */
  1590.         str[strlen(str)-1]=0;
  1591.         cp=strstr(line,str);
  1592.         if(c && cp!=line)
  1593.             cp=0; }
  1594.     else {
  1595.         cp=strstr(line,str);
  1596.         if(cp && c) {
  1597.             if(cp!=line || isalnum(*(cp+strlen(str))))
  1598.                 cp=0; }
  1599.         else {    /* must be isolated word */
  1600.             while(cp)
  1601.                 if((cp!=line && isalnum(*(cp-1)))
  1602.                     || isalnum(*(cp+strlen(str))))
  1603.                     cp=strstr(cp+strlen(str),str);
  1604.                 else
  1605.                     break; } }
  1606.     if(!cp && and) {
  1607.         true=0;
  1608.         break; }
  1609.     if(cp && or) {
  1610.         true=1;
  1611.         break; }
  1612.     if(cp)
  1613.         true=1; }
  1614. nest=0;
  1615. while((**ptrptr)!=')' && (**ptrptr)) {        /* handle nested exp */
  1616.     if((**ptrptr)=='(')                        /* (TRUE|(IGNORE)) */
  1617.         nest++;
  1618.     (*ptrptr)++;
  1619.     while((**ptrptr)==')' && nest && (**ptrptr)) {
  1620.         nest--;
  1621.         (*ptrptr)++; } }
  1622. (*ptrptr)++;    /* skip over ')' */
  1623. return(true);
  1624. }
  1625.  
  1626. /****************************************************************************/
  1627. /* Guru chat with the appearance of Local chat with sysop.                  */
  1628. /****************************************************************************/
  1629. void localguru(char *gurubuf, int gurunum)
  1630. {
  1631.     char    ch,str[256];
  1632.     int     con=console;         /* save console state */
  1633.  
  1634. if(sys_status&SS_GURUCHAT || !total_gurus)
  1635.     return;
  1636. sys_status|=SS_GURUCHAT;
  1637. console&=~(CON_L_ECHOX|CON_R_ECHOX);    /* turn off X's */
  1638. console|=(CON_L_ECHO|CON_R_ECHO);                    /* make sure echo is on */
  1639. if(action==NODE_CHAT) {    /* only page if from chat section */
  1640.     bprintf(text[PagingGuru],guru[gurunum]->name);
  1641.     ch=random(25)+25;
  1642.     while(ch--) {
  1643.         mswait(200);
  1644.         outchar('.'); } }
  1645. bprintf(text[SysopIsHere],guru[gurunum]->name);
  1646. getnodedat(node_num,&thisnode,1);
  1647. thisnode.aux=gurunum;
  1648. putnodedat(node_num,thisnode);
  1649. attr(color[clr_chatlocal]);
  1650. guruchat("HELLO",gurubuf,gurunum);
  1651. while(online && (sys_status&SS_GURUCHAT)) {
  1652.     checkline();
  1653.     action=NODE_GCHT;
  1654.     SYNC;
  1655.     if((ch=inkey(0))!=0) {
  1656.         ungetkey(ch);
  1657.         attr(color[clr_chatremote]);
  1658.         if(getstr(str,78,K_WRAP|K_CHAT)) {
  1659.             attr(color[clr_chatlocal]);
  1660.             guruchat(str,gurubuf,gurunum); } }
  1661.     else
  1662.         mswait(1); }
  1663. bputs(text[EndOfChat]);
  1664. sys_status&=~SS_GURUCHAT;
  1665. console=con;                /* restore console state */
  1666. }
  1667.  
  1668. /****************************************************************************/
  1669. /* Packs the password 'pass' into 5bit ASCII inside node_t. 32bits in         */
  1670. /* node.extaux, and the other 8bits in the upper byte of node.aux            */
  1671. /****************************************************************************/
  1672. void packchatpass(char *pass, node_t *node)
  1673. {
  1674.     char    bits;
  1675.     int        i,j;
  1676.  
  1677. node->aux&=~0xff00;        /* clear the password */
  1678. node->extaux=0L;
  1679. if((j=strlen(pass))==0) /* there isn't a password */
  1680.     return;
  1681. node->aux|=(int)((pass[0]-64)<<8);  /* 1st char goes in low 5bits of aux */
  1682. if(j==1)    /* password is only one char, we're done */
  1683.     return;
  1684. node->aux|=(int)((pass[1]-64)<<13); /* low 3bits of 2nd char go in aux */
  1685. node->extaux|=(long)((pass[1]-64)>>3); /* high 2bits of 2nd char go extaux */
  1686. bits=2;
  1687. for(i=2;i<j;i++) {    /* now process the 3rd char through the last */
  1688.     node->extaux|=(long)((long)(pass[i]-64)<<bits);
  1689.     bits+=5; }
  1690. }
  1691.  
  1692. /****************************************************************************/
  1693. /* Unpacks the password 'pass' from the 5bit ASCII inside node_t. 32bits in */
  1694. /* node.extaux, and the other 8bits in the upper byte of node.aux            */
  1695. /****************************************************************************/
  1696. char *unpackchatpass(char *pass, node_t node)
  1697. {
  1698.     char     bits;
  1699.     int     i;
  1700.  
  1701. pass[0]=(node.aux&0x1f00)>>8;
  1702. pass[1]=((node.aux&0xe000)>>13)|((node.extaux&0x3)<<3);
  1703. bits=2;
  1704. for(i=2;i<8;i++) {
  1705.     pass[i]=(node.extaux>>bits)&0x1f;
  1706.     bits+=5; }
  1707. pass[8]=0;
  1708. for(i=0;i<8;i++)
  1709.     if(pass[i])
  1710.         pass[i]+=64;
  1711. return(pass);
  1712. }
  1713.