home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / top2src.zip / PROCMSGS.C < prev    next >
C/C++ Source or Header  |  2000-07-13  |  54KB  |  1,348 lines

  1. /******************************************************************************
  2. PROCMSGS.C   Process all incoming TOP messages.
  3.  
  4.     Copyright 1993 - 2000 Paul J. Sidorsky
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License, version 2, as
  8.     published by the Free Software Foundation.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19. This module processes all incoming TOP messages from other node.  Most
  20. messages are handled directly in the process_messages() function, which
  21. accounts for its enormous size.  For a detailed list of the actual information
  22. needed by each message, see MESSAGES.TXT.
  23. ******************************************************************************/
  24.  
  25. #include "top.h"
  26.  
  27. /* process_messages() - Process all incoming TOP messages.
  28.    Parameters:  delname - TRUE to delete the name prompt, otherwise FALSE.
  29.    Returns:  Number of incoming messages processed.
  30. */
  31. XINT process_messages(char delname)
  32. {
  33. /* Loop counter, number of messages processed, number of messages used
  34.    (displayed), action flag, result code, delname override. */
  35. XINT d, proc = 0, mused = 0, isaction = 0, res, dn;
  36. msg_typ msgin; /* Incoming message buffer. */
  37. /* File name buffer, Temporary short string buffer (usually used for gender-
  38.    specific data in actions), test byte holder. */
  39. char filnam[256], ttt[10], tstbit[2];
  40. unsigned char allowbits = 0; /* Action token allow bits. */
  41. /* Temporary long number holder.  It is named cdc because it was originally
  42.    used for CyberDollar values with the games before they were removed. */
  43. unsigned long cdc;
  44. /* Incoming message file data.  No longer used. */
  45. struct ffblk mchg;
  46. char privchatflag = 0; /* Flag if we are entering private chat. */
  47. /* Unused game variables. */
  48. //|poker_game_typ mgame;
  49. //|char pokcount = 0;
  50. //|XINT pokstackgame[100];
  51. /* Flag if we need to return to the main channel, type of ban/invite
  52.    action. */
  53. char rettomain = 0, baninv = 0;
  54. /* Flag if the last message was used.  It is an int because the number of
  55.    the last message used (relative to mused) is needed, but it amounts to a
  56.    flag.  The sole purpose of this variable is to prevent extra newlines
  57.    in dual-window mode, which turned out to be a very involving process. */
  58. XINT lastmsgused;
  59. char nointerflg = 0; /* Flag if the Interrupt string has been sent. */
  60.  
  61. /*//|for (d = 0; d < 100; d++)
  62.     {
  63.     pokstackgame[d] = -1;
  64.     }*///|
  65.  
  66. /* Normal chat mode always needs the message prefix (which is what
  67.    lastmsgused essentially regulates), but dual window mode does not use it
  68.    on the first message to prevent double-spacing. */
  69. lastmsgused = !(user.pref1 & PREF1_DUALWINDOW);
  70. /* If the door kit sends a time message, it can't be sent as a TOP message
  71.    during message processing or it would throw TOP into an infinite loop. */
  72. blocktimemsgs = 1;
  73.  
  74. /* Scan our byte in the CHGIDX to see if we have new messages. */
  75. lseek(chgfil, (od_control.od_node), SEEK_SET);
  76. rec_locking(REC_LOCK, chgfil, (od_control.od_node), 1L);
  77. read(chgfil, tstbit, 1L);
  78. rec_locking(REC_UNLOCK, chgfil, (od_control.od_node), 1L);
  79.  
  80. /* If the byte was FALSE, we have no new messages. */
  81. if (!tstbit[0])
  82.     {
  83.     blocktimemsgs = 0;
  84.     return 0;
  85.     }
  86.  
  87. /* Clear the CHGIDX byte immediately. */
  88. tstbit[0] = 0;
  89. lseek(chgfil, (od_control.od_node), SEEK_SET);
  90. rec_locking(REC_LOCK, chgfil, (od_control.od_node), 1L);
  91. write(chgfil, tstbit, 1L);
  92. rec_locking(REC_UNLOCK, chgfil, (od_control.od_node), 1L);
  93.  
  94. if (user.pref1 & PREF1_DUALWINDOW)
  95.     {
  96.     /* In dual window mode, restore the last known position in the
  97.        lower (incoming messages) window. */
  98.     // Different for AVT when I find out what the store/recv codes are.
  99.     od_disp_emu("\x1B" "[u", TRUE);
  100.     top_output(OUT_SCREEN, getlang("DWOutputPrefix"));
  101.     }
  102.  
  103. /* Loop for each message indexed by the MIX file, processing if needed. */
  104. for (d = 0, dn = delname; d < filelength(midxinfil); d++)
  105.     {
  106.     /* Read the byte in the MIX file. */
  107.     res = lseek(midxinfil, (long) d, SEEK_SET);
  108.     if (res == -1)
  109.         {
  110.         continue;
  111.         }
  112.     rec_locking(REC_LOCK, midxinfil, d, 1L);
  113.     res = read(midxinfil, tstbit, 1L);
  114.     if (res == -1)
  115.         {
  116.         rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  117.         continue;
  118.         }
  119.     // This needs changing to a large, malloc()ed, buffered array to
  120.     // improve speed
  121.     if (!tstbit[0])
  122.         {
  123.         /* If the byte is 0, ignore the message as it has been processed
  124.            and is just leftover garbage. */
  125.         rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  126.         continue;
  127.         }
  128.  
  129.     /* Read the actual message. */
  130.     res = lseek(msginfil, (long) d * (long) sizeof(msg_typ), SEEK_SET);
  131.     if (res == -1)
  132.         {
  133.         rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  134.         continue;
  135.         }
  136.     rec_locking(REC_LOCK, msginfil, (long) d * (long) sizeof(msg_typ),
  137.                 (long) sizeof(msg_typ));
  138.     res = read(msginfil, &msgin, sizeof(msg_typ));
  139.     rec_locking(REC_UNLOCK, msginfil, (long) d * (long) sizeof(msg_typ),
  140.                 (long) sizeof(msg_typ));
  141.     if (res == -1)
  142.         {
  143.         rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  144.         continue;
  145.         }
  146.     /* The byte in the MIX file stays locked so other nodes don't write
  147.        a message in this spot before it's cleared. */
  148.  
  149.     if (msgin.channel != curchannel && msgin.channel != 0)
  150.         {
  151.         /* Ignore the message if it isn't global and isn't on our channel. */
  152.         tstbit[0] = 0;
  153.         lseek(midxinfil, (long) d, SEEK_SET);
  154.         write(midxinfil, tstbit, 1L);
  155.         rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  156.         continue;
  157.         }
  158.  
  159.     /* Do a little pre-processing preparation. */
  160.     isaction = baninv = 0;
  161.     fixname(msgin.handle, msgin.handle);
  162.  
  163.     /* At this time, some common steps in message processing will be
  164.        explained so they do not have to be commented each time below.
  165.  
  166.        !(forgetstatus[msgin.from] & FGT_FORGOTTEN) tests to make sure the
  167.            message isn't coming from someone that we've forgotten.  If it
  168.            is, most messages won't be processed.  This has to be done for
  169.            each message type because there are some messages that aren't
  170.            to be ignored even if the user is forgotten.  These messages
  171.            generally don't involve displaying anything on-screen.
  172.        proc++ increases the number of messages processed, which includes
  173.            ignored messages.
  174.        mused++ increases the number of messages actually used, so it does
  175.            not include ignored messages. */
  176.  
  177.     if (!dn && lastmsgused && (!forgetstatus[msgin.from] & FGT_FORGOTTEN))
  178.         {
  179.         /* Essentially, if this is the first message to be shown and the
  180.            user is using normal chat mode, a small string (usually ***) is
  181.            sent to let the user know that their typing is being interrupted.
  182.            This string is never sent if block while typing is on, but the
  183.            test is included for completeness. */
  184.         if (!(user.pref1 & PREF1_DUALWINDOW))
  185.             {
  186.             /* Only send the interrupt string if the user is in the process
  187.                of typing something (onflag == TRUE). */
  188.             if (!nointerflg && onflag && !(user.pref1 & PREF1_BLKWHILETYP))
  189.                 {
  190.                 top_output(OUT_SCREEN, getlang("Interrupt"));
  191.                 /* Don't send the interrupt string again. */
  192.                 nointerflg = 1;
  193.                 }
  194.             }
  195.         /* Send the message display prefix (usually just a newline). */
  196.         top_output(OUT_SCREEN, getlang("MsgDisplayPrefix"));
  197.         }
  198.  
  199.     /* The name prompt only has to be deleted once. */
  200.     dn = 0;
  201.     /* Many message types use a numeric value so it is obtained before
  202.        processing begins. */
  203.     cdc = strtoul(msgin.string, NULL, 10);
  204.  
  205.     /* The lastmsgused flag is figured from the mused total later on. */
  206.     lastmsgused = mused;
  207.  
  208.     /* Process each type of message.  Most processing is straightforward
  209.        (except for the common items covered above) so comments are kept
  210.        to a minimum. */
  211.     switch(msgin.type)
  212.         {
  213.         /* Normal text (talking). */
  214.         case MSG_TEXT:
  215.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  216.                 {
  217.                 delprompt(delname);
  218.                 top_output(OUT_SCREEN, getlang("MsgPrefix"), msgin.handle,
  219.                            msgin.string);
  220.                 mused++;
  221.                 }
  222.             proc++;
  223.             break;
  224.         /* A user has entered TOP. */
  225.         case MSG_ENTRY:
  226.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  227.                 {
  228.                 delprompt(delname);
  229.                 if (cfg.allowexmessages && msgin.string[0])
  230.                     {
  231.                     /* Send the user's entry message if they have one. */
  232.                     top_output(OUT_SCREEN, getlang("EMsgPrefix"),
  233.                                msgin.string);
  234.                     }
  235.                 else
  236.                     {
  237.                     /* Send the default entry message. */
  238.                     top_output(OUT_SCREEN, getlang("EMessage"), msgin.handle);
  239.                     }
  240.                 mused++;
  241.                 }
  242.             proc++;
  243.             /* Add the new user to the active nodes index and reset the
  244.                forget data for the user's node. */
  245.             fixname(handles[msgin.from].string, msgin.handle);
  246.             activenodes[msgin.from] = 1;
  247.             forgetstatus[msgin.from] = 0;
  248.             break;
  249.         /* A user has left TOP normally (with the QUIT command). */
  250.         case MSG_EXIT:
  251.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  252.                 {
  253.                 delprompt(delname);
  254.                 if (cfg.allowexmessages && msgin.string[0])
  255.                     {
  256.                     /* Send the user's exit message if they have one. */
  257.                     top_output(OUT_SCREEN, getlang("XMsgPrefix"),
  258.                                msgin.string);
  259.                     }
  260.                 else
  261.                     {
  262.                     /* Send the default exit message. */
  263.                     top_output(OUT_SCREEN, getlang("XMessage"), msgin.handle);
  264.                     }
  265.                 mused++;
  266.                 }
  267.             /* Reset private chat variables if they involve the node that is
  268.                leaving. */
  269.             if (privchatin == msgin.from) privchatin = -1;
  270.             if (privchatout == msgin.from) privchatout = -1;
  271.             activenodes[msgin.from] = 0;
  272.             forgetstatus[msgin.from] = 0;
  273.             /* If we are currently in the personal channel of the user that
  274.                is leaving, we must return to the main channel. */
  275.             if (curchannel ==
  276.                 ((unsigned long) msgin.from + 4000000000UL))
  277.                 {
  278.                 top_output(OUT_SCREEN, getlang("NoLongerOnSystem"),
  279.                            handles[msgin.from].string);
  280.                 rettomain = 1;
  281.                 }
  282.             proc++;
  283.             break;
  284.         /* A user entered the profile editor. */
  285.         case MSG_INEDITOR:
  286.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  287.                 {
  288.                 delprompt(delname);
  289.                 top_output(OUT_SCREEN, getlang("InProf"), msgin.handle);
  290.                 mused++;
  291.                 }
  292.             /* Reset private chat variables if they involve the node that is
  293.                going in the editor. */
  294.             if (privchatin == msgin.from) privchatin = -1;
  295.             if (privchatout == msgin.from) privchatout = -1;
  296.             proc++;
  297.             break;
  298.         /* A user has returned from the profile editor. */
  299.         case MSG_OUTEDITOR:
  300.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  301.                 {
  302.                 delprompt(delname);
  303.                 top_output(OUT_SCREEN, getlang("OutProf"), msgin.handle);
  304.                 mused++;
  305.                 }
  306.             proc++;
  307.             break;
  308.         /* Private text, just to us. */
  309.         case MSG_WHISPER:
  310.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  311.                 {
  312.                 delprompt(delname);
  313.                 top_output(OUT_SCREEN, getlang("WhisperPrefix"), msgin.handle,
  314.                            msgin.string);
  315.                 mused++;
  316.                 }
  317.             proc++;
  318.             break;
  319.         /* General action. */
  320.         case MSG_GA:
  321.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN) &&
  322.                 !(user.pref2 & PREF2_ACTIONSOFF))
  323.                 {
  324.                 delprompt(delname);
  325.                 top_output(OUT_SCREEN, getlang("GAPrefix"), msgin.handle,
  326.                            msgin.string);
  327.                 mused++;
  328.                 }
  329.             proc++;
  330.             break;
  331.         /* Posessive general action (largely the same as a normal GA). */
  332.         case MSG_GA2:
  333.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN) &&
  334.                 !(user.pref2 & PREF2_ACTIONSOFF))
  335.                 {
  336.                 delprompt(delname);
  337.                 top_output(OUT_SCREEN, getlang("GA2Prefix"), msgin.handle,
  338.                            msgin.string);
  339.                 mused++;
  340.                 }
  341.             proc++;
  342.             break;
  343.  
  344.         /* Actions are handled commonly at the end of the processing loop.
  345.            For now, flag the message as being an action and determine the
  346.            % tokens to allow based on type. */
  347.  
  348.         /* Singular action verb. */
  349.         case MSG_ACTIONSIN:
  350.             isaction = 1;
  351.             allowbits = ALLOW_ME | ALLOW_SEX | ALLOW_SLF | ALLOW_HESHE;
  352.             proc++;
  353.             break;
  354.         /* Plural action ("done to" somebody). */
  355.         case MSG_ACTIONPLU:
  356.             isaction = 1;
  357.             allowbits = ALLOW_ME | ALLOW_YOU | ALLOW_SEX | ALLOW_POS |
  358.                         ALLOW_SLF | ALLOW_HESHE;
  359.             proc++;
  360.             break;
  361.         /* Singular talktype verb. */
  362.         case MSG_TLKTYPSIN:
  363.             isaction = 1;
  364.             allowbits = ALLOW_ME | ALLOW_SEX | ALLOW_SLF | ALLOW_HESHE;
  365.             proc++;
  366.             break;
  367.         /* Plural talktype (contains text). */
  368.         case MSG_TLKTYPPLU:
  369.             isaction = 1;
  370.             allowbits = ALLOW_ME | ALLOW_SEX | ALLOW_SLF | ALLOW_HESHE;
  371.             proc++;
  372.             break;
  373.         /* Secret (private) plural action that was done to us. */
  374.         case MSG_ACTPLUSEC:
  375.             isaction = 1;
  376.             allowbits = ALLOW_ME | ALLOW_YOU | ALLOW_SEX | ALLOW_POS |
  377.                         ALLOW_SLF | ALLOW_HESHE;
  378.             proc++;
  379.             break;
  380.         /* A user has changed their TOP handle. */
  381.         case MSG_HANDLECHG:
  382.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  383.                 {
  384.                 delprompt(delname);
  385.                 if (msgin.gender == 0)
  386.                     {
  387.                     strcpy(ttt, getlang("His"));
  388.                     }
  389.                 if (msgin.gender == 1)
  390.                     {
  391.                     strcpy(ttt, getlang("Her"));
  392.                     }
  393.                 fixname(msgin.string, msgin.string);
  394.                 top_output(OUT_SCREEN, getlang("HandleChangeMsg"),
  395.                            handles[msgin.from].string, ttt, msgin.string);
  396.                 mused++;
  397.                 }
  398.             /* Update the handle in the main handle index. */
  399.             fixname(handles[msgin.from].string, msgin.string);
  400.             proc++;
  401.             break;
  402.         /* A user has changed their biography. */
  403.         case MSG_BIOCHG:
  404.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  405.                 {
  406.                 delprompt(delname);
  407.                 if (msgin.gender == 0)
  408.                     {
  409.                     strcpy(ttt, getlang("His"));
  410.                     }
  411.                 if (msgin.gender == 1)
  412.                     {
  413.                     strcpy(ttt, getlang("Her"));
  414.                     }
  415.                 mused++;
  416.                 top_output(OUT_SCREEN, getlang("BioChangeMsg"), msgin.handle,
  417.                            ttt);
  418.                 }
  419.             proc++;
  420.             break;
  421.         /* A user has changed genders. */
  422.         case MSG_SEXCHG:
  423.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  424.                 {
  425.                 delprompt(delname);
  426.                 top_output(OUT_SCREEN, getlang("SexChangeMsg"), msgin.handle,
  427.                            msgin.string);
  428.                 mused++;
  429.                 }
  430.             proc++;
  431.             break;
  432.         /* A user has changed their personal actions. */
  433.         case MSG_PERACTCHG:
  434.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  435.                 {
  436.                 delprompt(delname);
  437.                 if (msgin.gender == 0)
  438.                     {
  439.                     strcpy(ttt, getlang("His"));
  440.                     }
  441.                 if (msgin.gender == 1)
  442.                     {
  443.                     strcpy(ttt, getlang("Her"));
  444.                     }
  445.                 top_output(OUT_SCREEN, getlang("PersActChangeMsg"), msgin.handle, ttt);
  446.                 mused++;
  447.                 }
  448.             proc++;
  449.             break;
  450.         /* A user left TOP abruptly (carrier drop, time expired, etc.) */
  451.         case MSG_TOSSOUT:
  452.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  453.                 {
  454.                 delprompt(delname);
  455.                 top_output(OUT_SCREEN, getlang("TossOut"), msgin.handle);
  456.                 mused++;
  457.                 }
  458.             /* The same post-processing is done as for a normal exit. */
  459.             activenodes[msgin.from] = 0;
  460.             forgetstatus[msgin.from] = 0;
  461.             if (curchannel ==
  462.                 ((unsigned long) msgin.from + 4000000000UL))
  463.                 {
  464.                 top_output(OUT_SCREEN, getlang("NoLongerOnSystem"),
  465.                            handles[msgin.from].string);
  466.                 rettomain = 1;
  467.                 }
  468.             proc++;
  469.             break;
  470.         /* A user has just "forgotten" us. */
  471.         case MSG_FORGET:
  472.             /* Note that we have been forgotten, so we can tell the user
  473.                later if they try to do something to this user. */
  474.             forgetstatus[msgin.from] |= FGT_HASFORGOTME;
  475.             /* Reset private chat variables. */
  476.             if (privchatin == msgin.from) privchatin = -1;
  477.             if (privchatout == msgin.from) privchatout = -1;
  478.             proc++;
  479.             break;
  480.         /* A user has just "remembered" us. */
  481.         case MSG_REMEMBER:
  482.             /* Note that we are no longer forgotten by resetting the
  483.                HasForgotMe bit. */
  484.             forgetstatus[msgin.from] &= (255 - FGT_HASFORGOTME);
  485.             proc++;
  486.             break;
  487.         // these 3 probably need forget mods later on.
  488.         
  489.         /* Although TOP itself currently does not have link support, it may
  490.            in the future, which is why the three link messages were put in.
  491.            However, the external TOPLink utility does in fact use the link
  492.            messages so they should be supported. */
  493.  
  494.         /* A link has just been established to another BBS. */
  495.         case MSG_LINKUP:
  496.             delprompt(delname);
  497.             top_output(OUT_SCREEN, getlang("LinkOn"), msgin.handle, msgin.string);
  498.             strcpy(handles[msgin.from].string, msgin.string);
  499.             mused++;
  500.             proc++;
  501.             break;
  502.         /* Text received from a linked BBS. */
  503.         case MSG_LINKTEXT:
  504.             delprompt(delname);
  505.             top_output(OUT_SCREEN, getlang("LinkPrefix"), msgin.handle, msgin.string);
  506.             mused++;
  507.             proc++;
  508.             break;
  509.         /* The link to another BBS has been disconnected. */
  510.         case MSG_UNLINK:
  511.             delprompt(delname);
  512.             top_output(OUT_SCREEN, getlang("LinkOff"), msgin.handle);
  513.             strcpy(handles[msgin.from].string, msgin.string);
  514.             activenodes[msgin.from] = 0;
  515.             forgetstatus[msgin.from] = 0;
  516.             mused++;
  517.             proc++;
  518.             break;
  519.         /* A user has changed their entry or exit message. */
  520.         case MSG_EXMSGCHG:
  521.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  522.                 {
  523.                 delprompt(delname);
  524.                 if (msgin.gender == 0)
  525.                     {
  526.                     strcpy(ttt, getlang("His"));
  527.                     }
  528.                 if (msgin.gender == 1)
  529.                     {
  530.                     strcpy(ttt, getlang("Her"));
  531.                     }
  532.                 top_output(OUT_SCREEN, getlang("EXMsgChange"), msgin.handle, ttt);
  533.                 mused++;
  534.                 }
  535.             proc++;
  536.             break;
  537.         /* A sysop just tossed us back to the BBS. */
  538.         case MSG_TOSSED:
  539.             delprompt(delname);
  540.             top_output(OUT_SCREEN, getlang("HasTossed"), msgin.handle);
  541.             if (msgin.string[0])
  542.                 {
  543.                 top_output(OUT_SCREEN, getlang("TossComment"), msgin.string);
  544.                 }
  545.             tstbit[0] = 0;
  546.             lseek(midxinfil, (long) d, SEEK_SET);
  547.             write(midxinfil, tstbit, 1L);
  548.             rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  549.             od_exit(6, FALSE);
  550.             /* Processing continues in case the exit fails. */
  551.             proc++;
  552.             mused++;
  553.             break;
  554.         /* A sysop disconnected us from TOP and the BBS. */
  555.         case MSG_ZAPPED:
  556.             delprompt(delname);
  557.             top_output(OUT_SCREEN, getlang("HasZapped"), msgin.handle);
  558.             if (msgin.string[0])
  559.                 {
  560.                 top_output(OUT_SCREEN, getlang("TossComment"), msgin.string);
  561.                 }
  562.             tstbit[0] = 0;
  563.             lseek(midxinfil, (long) d, SEEK_SET);
  564.             write(midxinfil, tstbit, 1L);
  565.             rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  566.             od_exit(7, TRUE);
  567.             /* Processing continues in case the exit fails. */
  568.             proc++;
  569.             mused++;
  570.             break;
  571.         /* A sysop has reset a crashed node. */
  572.         case MSG_CLEARNODE:
  573.             delprompt(delname);
  574.             itoa(cdc, outnum[0], 10);
  575.             top_output(OUT_SCREEN, getlang("HasCleared"), outnum[0],
  576.                        handles[(XINT) cdc].string, msgin.handle);
  577.             check_nodes_used(FALSE);
  578.             mused++;
  579.             proc++;
  580.             break;
  581. /* Sysop CyberCash transactions, not currently used. */
  582. /*        case MSG_SYSGIVECD:
  583.             delprompt(delname);
  584.             ultoa(cdc, outnum[0], 10);
  585.             top_output(OUT_SCREEN, getlang("CDGive"), msgin.handle, outnum[0],
  586.                        cdc == 1 ? getlang("CDSingular") :
  587.                                   getlang("CDPlural"));
  588.             user.cybercash += cdc;
  589.             save_user_data(user_rec_num, &user);
  590.             mused++;
  591.             proc++;
  592.             break;
  593.         case MSG_SYSTAKECD:
  594.             delprompt(delname);
  595.             ultoa(cdc, outnum[0], 10);
  596.             top_output(OUT_SCREEN, getlang("CDTake"), msgin.handle, outnum[0],
  597.                        cdc == 1 ? getlang("CDSingular") :
  598.                                   getlang("CDPlural"));
  599.             user.cybercash -= cdc;
  600.             save_user_data(user_rec_num, &user);
  601.             mused++;
  602.             proc++;
  603.             break;
  604.         case MSG_SYSSETCD:
  605.             delprompt(delname);
  606.             ultoa(cdc, outnum[0], 10);
  607.             top_output(OUT_SCREEN, getlang("CDSet"), msgin.handle, outnum[0]);
  608.             user.cybercash = cdc;
  609.             save_user_data(user_rec_num, &user);
  610.             mused++;
  611.             proc++;
  612.             break;*///!
  613. /* A poker game message, currently unused. */
  614. /*//|        case MSG_POKER:
  615.             poker_core(msgin.data1, msgin.string);
  616.             if (msgextradata == 1)
  617.                 {
  618.                 pokstackgame[pokcount++] = msgin.data1;
  619.                 }
  620.             if (stricmp(msgin.string, "GameOver") &&
  621.                 stricmp(msgin.string, "DoRescan"))
  622.                 {
  623.                 mused++;
  624.                 }
  625.             proc++;
  626.             break;*///|
  627.         /* Generic text (usually system messages) to be displayed verbatim. */
  628.         case MSG_GENERIC:
  629.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  630.                 {
  631.                 delprompt(delname);
  632.                 top_output(OUT_SCREEN, msgin.string);
  633.                 mused++;
  634.                 }
  635.             proc++;
  636.             break;
  637.         /* A user has joined our current channel. */
  638.         case MSG_INCHANNEL:
  639.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  640.                 {
  641.                 delprompt(delname);
  642.                 top_output(OUT_SCREEN, getlang("ChannelIn"),
  643.                            msgin.handle);
  644.                 mused++;
  645.                 }
  646.             proc++;
  647.             break;
  648.         /* A user has left our current channel. */
  649.         case MSG_OUTCHANNEL:
  650.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  651.                 {
  652.                 delprompt(delname);
  653.                 top_output(OUT_SCREEN, getlang("ChannelOut"),
  654.                            msgin.handle);
  655.                 mused++;
  656.                 }
  657.             proc++;
  658.             break;
  659.         /* Crash protection has detected a stuck node. */
  660.         case MSG_KILLCRASH:
  661.             res = atoi(msgin.string);
  662.             delprompt(delname);
  663.             top_output(OUT_SCREEN, getlang("CrashToss"),
  664.                        msgin.string);
  665.             /* Clear the node's variables so it does not remain visible. */
  666.             activenodes[res] = 0;
  667.             forgetstatus[res] = 0;
  668.             mused++;
  669.             proc++;
  670.             break;
  671.         /* Directed message (not necessarily to us). */
  672.         case MSG_DIRECTED:
  673.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  674.                 {
  675.                 delprompt(delname);
  676.                 top_output(OUT_SCREEN, getlang("DirectedPrefix"),
  677.                            handles[msgin.from].string,
  678.                            msgin.doneto == od_control.od_node ?
  679.                            getlang("You") : handles[msgin.doneto].string,
  680.                            msgin.string);
  681.                 mused++;
  682.                 }
  683.             proc++;
  684.             break;
  685. /* The sysop has edited the user on this node.  Not used. */
  686. /*        case MSG_SYSUSEREDITED:
  687.             delprompt(delname);
  688.             top_output(OUT_SCREEN, getlang("SysopUserEdited"),
  689.                        msgin.string);
  690.             load_user_data(user_rec_num, &user);
  691.             mused++;
  692.             proc++;
  693.             break;*/
  694.         /* The sysop has changed our security level. */
  695.         case MSG_SYSSETSEC:
  696.             delprompt(delname);
  697.             ultoa(cdc, outnum[0], 10);
  698.             top_output(OUT_SCREEN, getlang("SecChangeMsg"),
  699.                        msgin.handle, outnum[0]);
  700.             /* Update that security level in the user and NODEIDX files. */
  701.             user.security = cdc;
  702.             save_user_data(user_rec_num, &user);
  703.             node->security = cdc;
  704.             save_node_data(od_control.od_node, node);
  705.             mused++;
  706.             proc++;
  707.             break;
  708.         /* A user has entered private chat mode. */
  709.         case MSG_INPRIVCHAT:
  710.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  711.                 {
  712.                 delprompt(delname);
  713.                 top_output(OUT_SCREEN, getlang("PrivChatIn"),
  714.                            msgin.handle);
  715.                 mused++;
  716.                 }
  717.             proc++;
  718.             break;
  719.         /* A user has returned from private chat mode. */
  720.         case MSG_OUTPRIVCHAT:
  721.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  722.                 {
  723.                 delprompt(delname);
  724.                 top_output(OUT_SCREEN, getlang("PrivChatOut"),
  725.                            msgin.handle);
  726.                 mused++;
  727.                 }
  728.             proc++;
  729.             break;
  730.         /* A user is requesting a private chat with us. */
  731.         case MSG_WANTSPRIVCHAT:
  732.             if (privchatout >= 0 && msgin.from == privchatout)
  733.                 {
  734.                 /* If we have previously requested to chat with the other
  735.                    user, enter private chat mode after processing is done. */
  736.                 privchatflag = 1;
  737.                 }
  738.             /* The other user initiated the chat request. */
  739.             if (privchatin < 0 && privchatout < 0)
  740.                 {
  741.                 privchatin = msgin.from;
  742.                 delprompt(delname);
  743.                 top_output(OUT_SCREEN, getlang("PrivChatRequested"),
  744.                            msgin.handle);
  745.                 }
  746.             mused++;
  747.             proc++;
  748.             break;
  749.         /* A user has denied this user's request for a private chat. */
  750.         case MSG_DENYPRIVCHAT:
  751.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  752.                 {
  753.                 delprompt(delname);
  754.                 top_output(OUT_SCREEN, getlang("PrivChatDenied"),
  755.                            msgin.handle);
  756.                 privchatout = -1;
  757.                 mused++;
  758.                 }
  759.             proc++;
  760.             break;
  761.         /* A moderator has changed our current channel's topic. */
  762.         case MSG_CHANTOPICCHG:
  763.             delprompt(delname);
  764.             top_output(OUT_SCREEN, getlang("TopicChangeMsg"),
  765.                        handles[msgin.from].string, msgin.string);
  766.             strcpy(cmibuf.topic, msgin.string);
  767.             mused++;
  768.             proc++;
  769.             break;
  770.         /* BAN, UNBAN, INVITE, and UNINVITE commands from a channel
  771.            moderator, not necessarily done to us.  They are processed
  772.            collectively later. */
  773.         case MSG_CHANBANNED:
  774.         case MSG_CHANUNBANNED:
  775.         case MSG_CHANINVITED:
  776.         case MSG_CHANUNINVITED:
  777.             baninv = (msgin.type - MSG_CHANBANNED) + 1;
  778.             mused++;
  779.             proc++;
  780.             break;
  781.         /* Another user (which could be us) has been made the moderator
  782.            of our current channel. */
  783.         case MSG_CHANMODCHG:
  784.             delprompt(delname);
  785.             top_output(OUT_SCREEN, getlang("ModChangeMsg"),
  786.                        handles[msgin.from].string,
  787.                        msgin.doneto == od_control.od_node ?
  788.                            getlang("You") : handles[msgin.doneto].string);
  789.             cmibuf.modnode = msgin.doneto;
  790.             mused++;
  791.             proc++;
  792.             break;
  793.         /* Force an update of the active nodes index.  Not currently used
  794.            by TOP or any known utility. */
  795.         case MSG_FORCERESCAN:
  796.             check_nodes_used(FALSE);
  797.             proc++;
  798.             break;
  799.         /* A user has entered the biography editor. */
  800.         case MSG_INBIOEDITOR:
  801.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  802.                 {
  803.                 delprompt(delname);
  804.                 top_output(OUT_SCREEN, getlang("InBioEditor"),
  805.                            msgin.handle);
  806.                 mused++;
  807.                 }
  808.             if (privchatin == msgin.from) privchatin = -1;
  809.             if (privchatout == msgin.from) privchatout = -1;
  810.             proc++;
  811.             break;
  812.         /* A user has returned from the biography editor. */
  813.         case MSG_OUTBIOEDITOR:
  814.             if (!(forgetstatus[msgin.from] & FGT_FORGOTTEN))
  815.                 {
  816.                 delprompt(delname);
  817.                 top_output(OUT_SCREEN, getlang("OutBioEditor"),
  818.                            msgin.handle);
  819.                 mused++;
  820.                 }
  821.             proc++;
  822.             break;
  823.         }
  824.  
  825.     /* Handle incoming actions. */
  826.     if (isaction && !(forgetstatus[msgin.from] & FGT_FORGOTTEN) &&
  827.         !(user.pref2 & PREF2_ACTIONSOFF))
  828.         {
  829.         /* Action text buffer, pictorial action buffer, pictorial action
  830.            extension buffer, final action text pointer, temporary character
  831.            exchange holder. */
  832.         char *tmp = NULL, *buf = NULL, texbuf[5], *str = NULL, xch;
  833.         /* Counter, flag when a % is incountered, flag to process % tokens,
  834.            flag if we're using a dynamic buffer, end of string marker. */
  835.         XINT c, nxt = 0, proctokon = 1, dynam, tmark = 0;
  836.  
  837.         dynam = 0;
  838.         /* Immediately determine if this is a pictorial action.  Pictorial
  839.            actions require a different setup because of their larger size. */
  840.         if (!strnicmp(msgin.string, "%P", 2))
  841.             {
  842.             FILE *fil = NULL; /* Pictorial action file stream. */
  843.  
  844.             /* Although it was omitted from the TOP docs, it is possible to
  845.                specify a path along with a pictorial action file base name. */
  846.             if (strchr(&msgin.string[2], ':') == NULL &&
  847.                 strchr(&msgin.string[2], '\\') == NULL)
  848.                 {
  849.                 /* No path characters found, so assume the TOP ANSI Path. */
  850.                 sprintf(outbuf, "%s%s", cfg.topansipath, &msgin.string[2]);
  851.                 }
  852.             else
  853.                 {
  854.                 /* Use the path as is. */
  855.                 strcpy(outbuf, &msgin.string[2]);
  856.                 }
  857.             get_extension(outbuf, texbuf);
  858.             strcat(outbuf, texbuf);
  859.  
  860.             /* Open the pictorial action file. */
  861.             fil = fopen(outbuf, "rb");
  862.             if (!fil)
  863.                 {
  864.                 // Err msg
  865.                 }
  866.             /* An extra byte is needed because the entire file is treated
  867.                as one big string. */
  868.             buf = malloc(filelength(fileno(fil)) + 1);
  869.             if (buf != NULL)
  870.                 {
  871.                 /* Read in the entire file. */
  872.                 memset(buf, 0, filelength(fileno(fil)) + 1);
  873.                 dynam = 1;
  874.                 rewind(fil);
  875.                 fread(buf, 1, filelength(fileno(fil)), fil);
  876.                 }
  877.             fclose(fil);
  878.             }
  879.  
  880.         /* Allocate a larger temporary buffer to hold the translated output
  881.            text. */
  882.         if (!dynam || buf != NULL)
  883.             {
  884.             /* 1000 extra bytes are allocated to minimize chances of a
  885.                buffer overrun due to excessive % tokens. */
  886.             tmp = malloc(dynam ?
  887.                     (strlen(buf) + 1000) : (strlen(msgin.string) + 1000));
  888.             }
  889.         if (tmp != NULL)
  890.             {
  891.             memset(tmp, 0,
  892.                 (dynam ? (strlen(buf) + 1000) : (strlen(msgin.string) + 1000)));
  893.             delprompt(delname);
  894.             mused++;
  895.             /* Assign a common string pointer to whatever buffer we are
  896.                using, for manageability. */
  897.             if (dynam)
  898.                 {
  899.                 str = buf;
  900.                 }
  901.             else
  902.                 {
  903.                 str = msgin.string;
  904.                 }
  905.  
  906.             /* Loop for each character in the buffer. */
  907.             for (c = 0; c < (dynam ? strlen(buf) : strlen(msgin.string));
  908.                  c++)
  909.                 {
  910.                 if (msgin.type == MSG_TLKTYPPLU && c == msgin.data1)
  911.                     {
  912.                     /* Disable token processing once we reach the user's
  913.                        text in a talktype, so they can't wreak havoc with
  914.                        extra % codes. */
  915.                     proctokon = 0;
  916.                     }
  917.                 if (nxt)
  918.                     {
  919.                     /* The previous character was a %, so we expect a
  920.                        token character. */
  921.  
  922.                     nxt = 2;
  923.  
  924.                     /* For token explanations, see TOP.DOC. */
  925.  
  926.                     /* "Me" token. */
  927.                     if (toupper(str[c]) == 'M' &&
  928.                         (allowbits & ALLOW_ME))
  929.                         {
  930.                         tmark = strlen(tmp);
  931.                         strcat(tmp, top_output(OUT_STRINGNF,
  932.                                                getlang("ActionMe"),
  933.                                                msgin.handle));
  934.                         /* Adjust the start of user text (normally used
  935.                            in talktypes). */
  936.                         msgin.data1 -= 2L;
  937.                         msgin.data1 += (long) strlen(tmp) - (long) tmark;
  938.                         }
  939.                     /* "You" token. */
  940.                     if (toupper(str[c]) == 'Y' &&
  941.                         (allowbits & ALLOW_YOU))
  942.                         {
  943.                         tmark = strlen(tmp);
  944.                         strcat(tmp, top_output(OUT_STRINGNF,
  945.                                                getlang("ActionYouPrefix")));
  946.                         if (msgin.doneto == od_control.od_node)
  947.                             {
  948.                             strcat(tmp, getlang("You"));
  949.                             }
  950.                         if (msgin.doneto == -2)
  951.                             {
  952.                             strcat(tmp, getlang("All"));
  953.                             }
  954.                         if ((msgin.doneto >= 0) &&
  955.                             (msgin.doneto != od_control.od_node))
  956.                             {
  957.                             strcat(tmp, handles[msgin.doneto].string);
  958.                             }
  959.                         strcat(tmp, top_output(OUT_STRINGNF,
  960.                                                getlang("ActionYouSuffix")));
  961.                         /* Adjust the start of user text (normally used
  962.                            in talktypes). */
  963.                         msgin.data1 -= 2L;
  964.                         msgin.data1 += (long) strlen(tmp) - (long) tmark;
  965.                         }
  966.                     /* "His/Her" token. */
  967.                     if (toupper(str[c]) == 'H' &&
  968.                         (allowbits & ALLOW_SEX))
  969.                         {
  970.                         tmark = strlen(tmp);
  971.                         strcat(tmp, top_output(OUT_STRINGNF,
  972.                                                getlang("ActionHisHerPrefix")));
  973.                         if (msgin.gender == 0)
  974.                             {
  975.                             strcat(tmp, getlang("His"));
  976.                             }
  977.                         if (msgin.gender == 1)
  978.                             {
  979.                             strcat(tmp, getlang("Her"));
  980.                             }
  981.                         strcat(tmp, top_output(OUT_STRINGNF,
  982.                                                getlang("ActionHisHerSuffix")));
  983.                         /* Adjust the start of user text (normally used
  984.                            in talktypes). */
  985.                         msgin.data1 -= 2L;
  986.                         msgin.data1 += (long) strlen(tmp) - (long) tmark;
  987.                         }
  988.                     /* "He/She" token. */
  989.                     if (toupper(str[c]) == 'E' &&
  990.                         (allowbits & ALLOW_HESHE))
  991.                         {
  992.                         tmark = strlen(tmp);
  993.                         strcat(tmp, top_output(OUT_STRINGNF,
  994.                                                getlang("ActionHeShePrefix")));
  995.                         if (msgin.gender == 0)
  996.                             {
  997.                             strcat(tmp, getlang("He"));
  998.                             }
  999.                         if (msgin.gender == 1)
  1000.                             {
  1001.                             strcat(tmp, getlang("She"));
  1002.                             }
  1003.                         strcat(tmp, top_output(OUT_STRINGNF,
  1004.                                                getlang("ActionHeSheSuffix")));
  1005.                         /* Adjust the start of user text (normally used
  1006.                            in talktypes). */
  1007.                         msgin.data1 -= 2L;
  1008.                         msgin.data1 += (long) strlen(tmp) - (long) tmark;
  1009.                         }
  1010.                     /* "Himself/Herself" token. */
  1011.                     if (toupper(str[c]) == 'F' &&
  1012.                         (allowbits & ALLOW_SLF))
  1013.                         {
  1014.                         tmark = strlen(tmp);
  1015.                         strcat(tmp, top_output(OUT_STRINGNF,
  1016.                                                getlang("ActionSelfPrefix")));
  1017.                         if (msgin.gender == 0)
  1018.                             {
  1019.                             strcat(tmp, getlang("Himself"));
  1020.                             }
  1021.                         if (msgin.gender == 1)
  1022.                             {
  1023.                             strcat(tmp, getlang("Herself"));
  1024.                             }
  1025.                         strcat(tmp, top_output(OUT_STRINGNF,
  1026.                                                getlang("ActionSelfSuffix")));
  1027.                         /* Adjust the start of user text (normally used
  1028.                            in talktypes). */
  1029.                         msgin.data1 -= 2L;
  1030.                         msgin.data1 += (long) strlen(tmp) - (long) tmark;
  1031.                         }
  1032.                     /* Possessive token. */
  1033.                     if (toupper(str[c]) == 'S' &&
  1034.                         (allowbits & ALLOW_POS))
  1035.                         {
  1036.                         tmark = strlen(tmp);
  1037.                         if (msgin.doneto == od_control.od_node)
  1038.                             {
  1039.                             strcat(tmp, top_output(OUT_STRINGNF,
  1040.                                             getlang("ActionYour"),
  1041.                                             getlang("YourSuffix")));
  1042.                             }
  1043.                         else
  1044.                             {
  1045.                             strcat(tmp, top_output(OUT_STRINGNF,
  1046.                                             getlang("ActionPossessive"),
  1047.                                             getlang("Pers3Suffix")));
  1048.                             }
  1049.                         /* Adjust the start of user text (normally used
  1050.                            in talktypes). */
  1051.                         msgin.data1 -= 2L;
  1052.                         msgin.data1 += (long) strlen(tmp) - (long) tmark;
  1053.                         }
  1054.                     }
  1055.                 if (nxt == 0)
  1056.                     {
  1057.                     if (str[c] == '%' && proctokon)
  1058.                         {
  1059.                         /* Flag the next loop that a % was found. */
  1060.                         nxt = 1;
  1061.                         }
  1062.                     else
  1063.                         {
  1064.                         /* Copy the character as is. */
  1065.                         strncat(tmp, &str[c], 1);
  1066.                         }
  1067.                     }
  1068.                 /* Reset the next flag if it was used on this loop. */
  1069.                 if (nxt == 2)
  1070.                     {
  1071.                     nxt = 0;
  1072.                     }
  1073.                 }
  1074.  
  1075.             /* Append the user text if this is a plural talktype. */
  1076.             if (msgin.type == MSG_TLKTYPPLU)
  1077.                 {
  1078.                 /* Store the first character of user text and replace it
  1079.                    with a \0 so the action text can be printed. */
  1080.                 xch = tmp[msgin.data1];
  1081.                 tmp[msgin.data1] = '\0';
  1082.                 top_output(dynam ? OUT_EMULATE : OUT_SCREEN, tmp);
  1083.                 /* Restore the user text and print it with language code
  1084.                    translation turned off. */
  1085.                 tmp[msgin.data1] = xch;
  1086.                 top_output(dynam ? OUT_EMULATE : OUT_SCREEN, "@1&L",
  1087.                            &tmp[msgin.data1]);
  1088.                 }
  1089.             else
  1090.                 {
  1091.                 top_output(dynam ? OUT_EMULATE : OUT_SCREEN, tmp);
  1092.                 }
  1093.             /* Secret action. */
  1094.             if (msgin.type == MSG_ACTPLUSEC)
  1095.                 {
  1096.                 top_output(OUT_SCREEN, getlang("Secretly"));
  1097.                 }
  1098.             dofree(tmp);
  1099.             }
  1100.         if (dynam)
  1101.             {
  1102.             dofree(buf);
  1103.             }
  1104.         }
  1105.  
  1106.     /* BAN, UNBAN, INVITE, and UNINVITE commands. */
  1107.     if (baninv > 0)
  1108.         {
  1109.         delprompt(delname);
  1110.  
  1111.         /* These messages come in globally if the command affects us,
  1112.            otherwise they come in on the current channel as a notification. */
  1113.         if (msgin.channel != 0)
  1114.             {
  1115.             /* Notification. */
  1116.  
  1117.             /* Copy the right language item name based on the message. */
  1118.             switch (baninv)
  1119.                 {
  1120.                 case 1: strcpy(outbuf, "HasBeenBanned"); break;
  1121.                 case 2: strcpy(outbuf, "HasBeenUnBanned"); break;
  1122.                 case 3: strcpy(outbuf, "HasBeenInvited"); break;
  1123.                 case 4: strcpy(outbuf, "HasBeenUnInvited"); break;
  1124.                 }
  1125.             top_output(OUT_SCREEN, getlang(outbuf),
  1126.                        handles[msgin.from].string,
  1127.                        msgin.doneto == od_control.od_node ?
  1128.                            getlang("You") : handles[msgin.doneto].string);
  1129.             /* BAN and INVITE add the node to the special nodes list. */
  1130.             if (baninv == 1 || baninv == 3)
  1131.                 {
  1132.                 cmi_setspec(msgin.doneto, 1);
  1133.                 }
  1134.             /* UNBAN and UNINVITE remove the node from the special nodes
  1135.                list. */
  1136.             if (baninv == 2 || baninv == 4)
  1137.                 {
  1138.                 cmi_setspec(msgin.doneto, 0);
  1139.                 }
  1140.             if (baninv == 1 || baninv == 4)
  1141.                 {
  1142.                 /* If a BAN or UNINVITE command was done to us and we
  1143.                    received the notification, it means we are being thrown
  1144.                    out of our current channel, so we have to return the
  1145.                    user to the main channel. */
  1146.                 if (msgin.doneto == od_control.od_node)
  1147.                     {
  1148.                     rettomain = 1;
  1149.                     }
  1150.                 }
  1151.             }
  1152.         else
  1153.             {
  1154.             /* Global message that affects us. */
  1155.  
  1156.             /* Select the right language item. */
  1157.             /* A switch was not used here because compiler didn't like it
  1158.                for some reason, possibly due to the enormous switch used
  1159.                for message processing. */
  1160.             if (baninv == 1)
  1161.                 {
  1162.                 if ((unsigned long) msgin.data1 <= 3999999999UL)
  1163.                     strcpy(outbuf, "YouBannedChan");
  1164.                 if ((unsigned long) msgin.data1 >= 4000000000UL &&
  1165.                     (unsigned long) msgin.data1 <= 4000999999UL)
  1166.                     strcpy(outbuf, "YouBannedUserChan");
  1167.                 if ((unsigned long) msgin.data1 >= 4001000000UL)
  1168.                     strcpy(outbuf, "YouBannedConf");
  1169.                 }
  1170.             if (baninv == 2)
  1171.                 {
  1172.                 if ((unsigned long) msgin.data1 <= 3999999999UL)
  1173.                     strcpy(outbuf, "YouUnBannedChan");
  1174.                 if ((unsigned long) msgin.data1 >= 4000000000UL &&
  1175.                     (unsigned long) msgin.data1 <= 4000999999UL)
  1176.                     strcpy(outbuf, "YouUnBannedUsChan");
  1177.                 if ((unsigned long) msgin.data1 >= 4001000000UL)
  1178.                     strcpy(outbuf, "YouUnBannedConf");
  1179.                 }
  1180.             if (baninv == 3)
  1181.                 {
  1182.                 if ((unsigned long) msgin.data1 <= 3999999999UL)
  1183.                     strcpy(outbuf, "YouInvitedChan");
  1184.                 if ((unsigned long) msgin.data1 >= 4000000000UL &&
  1185.                     (unsigned long) msgin.data1 <= 4000999999UL)
  1186.                     strcpy(outbuf, "YouInvitedUsChan");
  1187.                 if ((unsigned long) msgin.data1 >= 4001000000UL)
  1188.                     strcpy(outbuf, "YouInvitedConf");
  1189.                 }
  1190.             if (baninv == 4)
  1191.                 {
  1192.                 if ((unsigned long) msgin.data1 <= 3999999999UL)
  1193.                     strcpy(outbuf, "YouUnInvitedChan");
  1194.                 if ((unsigned long) msgin.data1 >= 4000000000UL &&
  1195.                     (unsigned long) msgin.data1 <= 4000999999UL)
  1196.                     strcpy(outbuf, "YouUnInvitedUsCh");
  1197.                 if ((unsigned long) msgin.data1 >= 4001000000UL)
  1198.                     strcpy(outbuf, "YouUnInvitedConf");
  1199.                 }
  1200.             top_output(OUT_SCREEN, getlang(outbuf),
  1201.                        channelname((unsigned long) msgin.data1));
  1202.             }
  1203.         }
  1204.  
  1205.     /* Determine if the message just processed was actually used. */
  1206.     lastmsgused = mused - lastmsgused; /* TRUE if last used, FALSE if not. */
  1207.  
  1208.     /* Clear the bit for this message in the MIX file and finally unlock
  1209.        it. */
  1210.     tstbit[0] = 0;
  1211.     lseek(midxinfil, (long) d, SEEK_SET);
  1212.     write(midxinfil, tstbit, 1L);
  1213.     rec_locking(REC_UNLOCK, midxinfil, d, 1L);
  1214.     }
  1215.  
  1216. /* It is now safe for door kit time messages to be treated as TOP messages. */
  1217. blocktimemsgs = 0;
  1218.  
  1219. /* Some poker post-processing which is not used. */
  1220. /*//|for (res = 0; res < pokcount; res++)
  1221.     {
  1222.     poker_lockgame(pokstackgame[res]);
  1223.     poker_loadgame(pokstackgame[res], &mgame);
  1224.     poker_unlockgame(pokstackgame[res]);
  1225.  
  1226.     poker_sendmessage(MSG_POKER, 1, pokstackgame[res], 1, "Finished",
  1227.                       &mgame);
  1228.     }*///|
  1229.  
  1230. /* Enter private chat if needed. */
  1231. if (privchatflag)
  1232.     {
  1233.     dispatch_message(MSG_INPRIVCHAT, user.handle, -1, 0, 0);
  1234.     node->task |= TASK_PRIVATECHAT;
  1235.     save_node_data(od_control.od_node, node);
  1236.     cmi_busy();
  1237.     privatechat(privchatout);
  1238.     cmi_unbusy();
  1239.     node->task = node->task & (0xFF - TASK_PRIVATECHAT);
  1240.     save_node_data(od_control.od_node, node);
  1241.     dispatch_message(MSG_OUTPRIVCHAT, user.handle, -1, 0, 0);
  1242.     }
  1243.  
  1244. /* Return to main channel if needed. */
  1245. if (rettomain)
  1246.     {
  1247.     top_output(OUT_SCREEN, getlang("ReturnToMain"));
  1248.     /* Leave the current channel.  Even though the user is likely being
  1249.        forced out, it is actually voluntary as to whether TOP complies
  1250.        with the request to remove the user.  Obviously, this should always
  1251.        be done to prevent confusion for both other users and possibly TOP
  1252.        itself. */
  1253.     res = cmi_unjoin(curchannel);
  1254.     if (res != CMI_OKAY)
  1255.         {
  1256.         top_output(OUT_SCREEN, getlang("UnJoinError"));
  1257.         }
  1258.     /* Join the main channel. */
  1259.     res = cmi_join(cfg.defaultchannel);
  1260.     if (res != CMI_OKAY)
  1261.         {
  1262.         /* Join our personal channel if for some reason the main channel
  1263.            cannot be joined.  This likely means the CMI is corrupt. */
  1264.         res = cmi_join(4000000000UL + (unsigned long) od_control.od_node);
  1265.         if (res != CMI_OKAY)
  1266.             {
  1267.             top_output(OUT_SCREEN, getlang("SevereJoinError"));
  1268.             od_exit(230, FALSE);
  1269.             }
  1270.         else
  1271.             {
  1272.             curchannel = 4000000000UL + (unsigned long) od_control.od_node;
  1273.             }
  1274.         }
  1275.     node->channel = curchannel = cfg.defaultchannel;
  1276.     save_node_data(od_control.od_node, node);
  1277.     dispatch_message(MSG_INCHANNEL, "\0", -1, 0, 0);
  1278.     channelsummary();
  1279.     }
  1280.  
  1281. if (delname && mused > 0 && lastmsgused)
  1282.     {
  1283.     top_output(OUT_SCREEN, getlang("MessageTrailer"));
  1284.     }
  1285.  
  1286. if (user.pref1 & PREF1_DUALWINDOW)
  1287.     {
  1288.     /* "Reactivate" the upper window in dual window mode. */
  1289.     if (onflag)
  1290.         {
  1291.         top_output(OUT_SCREEN, getlang("DWRestorePrefix"));
  1292.         }
  1293.     // Different for AVT when I find out what the store/recv codes are.
  1294.     od_disp_emu("\x1B" "[s", TRUE);
  1295.  
  1296.     }
  1297.  
  1298. /* In dual window mode, TOP prepares the screen for a message before it is
  1299.    known if the message will actually be used.  Therefore, if no messages
  1300.    were used but at least one was processed, we have to fool the calling
  1301.    function into thinking at least one message was used so it will restore
  1302.    the screen. */
  1303. if (mused == 0 && (user.pref1 & PREF1_DUALWINDOW) && proc > 0)
  1304.     {
  1305.     mused = 1;
  1306.     }
  1307.  
  1308. return mused;
  1309. }
  1310.  
  1311. /* delprompt() - Deletes the name prompt.
  1312.    Parameters:  dname - Flag whether or not to delete the name (see notes).
  1313.    Return:  Nothing.
  1314.    Notes:  The dname parameter essentially controls whether or not this
  1315.            function actually does anything.  If it is TRUE, TOP will delete
  1316.            the name prompt as planned.  If it is FALSE, TOP will do nothing.
  1317.            This parameter is needed because the function can be called
  1318.            several times during message processing, but the name prompt
  1319.            only needs to be deleted once, and attempting to delete it
  1320.            multiple times would mess up the screen.
  1321. */
  1322. void delprompt(char dname)
  1323. {
  1324. XINT dd; /* Counter. */
  1325.  
  1326. if (dname)
  1327.     {
  1328.     if (user.pref1 & PREF1_DUALWINDOW)
  1329.         {
  1330.         /* At the moment, no action is taken under dual window mode. */
  1331.  //       top_output(OUT_SCREEN, getlang("DWClearInput"));
  1332.         }
  1333.     else
  1334.         {
  1335.         top_output(OUT_SCREEN, getlang("DelPromptPrefix"));
  1336.         /* Backspace out the name prompt. */
  1337.         for (dd = 0;
  1338.              dd < strlen(top_output(OUT_STRING, getlang("DefaultPrompt"),
  1339.                                     user.handle)); dd++)
  1340.             {
  1341.             top_output(OUT_SCREEN, getlang("DelPrompt"));
  1342.             }
  1343.         top_output(OUT_SCREEN, getlang("DelPromptSuffix"));
  1344.         }
  1345.     }
  1346.  
  1347. }
  1348.