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

  1. /******************************************************************************
  2. PROCINP.C    Process all TOP commands and input.
  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 TOP commands.  Many are handled right in the
  20. process_input() function, which accounts for its size.  Others (usually
  21. multi-word commands) are handled by separate processors in other modules which
  22. are called from this module.
  23. ******************************************************************************/
  24.  
  25. #include "top.h"
  26.  
  27. /* This macro is used to determine where the name starts in a whisper or
  28.    directed message.  If there is a space at the start of the string, then
  29.    shorthand mode was used (a single character).  Otherwise, longhand mode
  30.    was used (two full words). */
  31. #define spacecheck(xxxx) xxxx[0] == ' ' ? &xxxx[1] : &xxxx[0]
  32.  
  33. /* process_input() - Process all TOP commands and input.
  34.    Parameters:  string - Input string to process.
  35.    Returns:  Nothing.
  36. */
  37. void process_input(unsigned char *string)
  38. {
  39. /* Shorthand flags for message sent and echo GA preferences. */
  40. char msgsent = 1, echoga = 1;
  41. /* Private node to receive the message (not used), number of words in input
  42.    string, counter, command length holder, result code. */
  43. XINT priv = -1, numwds, z, cmdlen = 0, res;
  44. /* Action used flag, no longer used.  Was used with old single-list format. */
  45. // char auflg = 0;
  46. /* Node the message is destined for ("done to"). */
  47. XINT sendto;
  48. /* Command text holder, command handle holder. */
  49. unsigned char tmpstr[256], tmphand[256]; // Dynam with MAXSTRLEN!
  50.  
  51. /* Check incoming messages before processing.  This results in a more
  52.    realistic order for items to be displayed on screen. */
  53. process_messages(FALSE);
  54. /* Refresh active nodes. */
  55. check_nodes_used(FALSE);
  56.  
  57. /* Prepare the screen for a command response. */
  58. if (user.pref1 & PREF1_DUALWINDOW)
  59.     {
  60.     // Different for AVT when I find out what the store/recv codes are.
  61.     od_disp_emu("\x1B" "[u", TRUE);
  62.     top_output(OUT_SCREEN, getlang("DWOutputPrefix"));
  63.     }
  64. else
  65.     {
  66.     top_output(OUT_SCREEN, getlang("ResponsePrefix"));
  67.     }
  68.  
  69. /* Set preference aliases. */
  70. msgsent = user.pref1 & PREF1_MSGSENT;
  71. echoga = user.pref1 & PREF1_ECHOGA;
  72.  
  73. /* Censor the string. */
  74. if (numcensorwords > 0)
  75.     {
  76.     if (censorinput(string))
  77.         {
  78.         /* The censor blocked the input, so don't process it. */
  79.         return;
  80.         }
  81.     }
  82.  
  83. /* Split the string into words. */
  84. numwds = split_string(string);
  85.  
  86. /* Most commands are self-explanatory and simply call other functions to
  87.    respond to the command in detail. */
  88.  
  89. /* QUIT command (exit TOP). */
  90. if (checkcmdmatch(get_word(0), getlang("CmdsQuit")) > 0 &&
  91.     numwds == 1)
  92.     {
  93.     dispatch_message(MSG_EXIT, user.xmessage, -1, 0, 0);
  94.     unregister_node(1);
  95.     quit_top();
  96.     return;
  97.     }
  98. /* COMMANDS command (short list of all commands). */
  99. if (checkcmdmatch(get_word(0), getlang("CmdsCommands")) > 0 &&
  100.     numwds == 1)
  101.     {
  102.     minihelp();
  103.     return;
  104.     }
  105. /* HELP command. */
  106. if (checkcmdmatch(get_word(0), getlang("CmdsHelp")) > 0)
  107.     {
  108.     help_proc(numwds);
  109.     return;
  110.     }
  111. /* COLOURHELP command (PubColour code list). */
  112. if (checkcmdmatch(get_word(0), getlang("CmdsColourHelp")) > 0 &&
  113.     numwds == 1)
  114.     {
  115.     top_output(OUT_SCREEN, getlang("ColourHelpPrefix"));
  116.     show_file("COLHELP", SCRN_NONE);
  117.     return;
  118.     }
  119. /* ACTION multi-word command. */
  120. if (checkcmdmatch(get_word(0), getlang("CmdsAction")) > 0)
  121.     {
  122.     if (!cfg.allowactions)
  123.         {
  124.         top_output(OUT_SCREEN, getlang("ActionsNotAllowed"));
  125.         return;
  126.         }
  127.     if (user.security < cfg.actionusesec)
  128.         {
  129.         top_output(OUT_SCREEN, getlang("NoAccActUse"));
  130.         return;
  131.         }
  132.     action_proc(numwds);
  133.     return;
  134.     }
  135. /* TIME command. */
  136. if (checkcmdmatch(get_word(0), getlang("CmdsTime")) > 0 &&
  137.     numwds == 1)
  138.     {
  139.     show_time();
  140.     return;
  141.     }
  142. /* SCAN or WHO command (show who's in each channel). */
  143. if (checkcmdmatch(get_word(0), getlang("CmdsWho")) > 0 &&
  144.     numwds == 1)
  145.     {
  146.     scan_pub();
  147.     return;
  148.     }
  149. /* CDTOTAL command.  Not used, it was used with the games and was left in
  150.    for future upgradability.  It could also be used with BJ4TOP if BJ4TOP
  151.    stored the cybercash in the TOP user file, as there is already space
  152.    reserved in the file for a cybercash total. */
  153. if (checkcmdmatch(get_word(0), getlang("CmdsCDTotal")) > 0 &&
  154.     numwds == 1)
  155.     {
  156.     ultoa(user.cybercash, outnum[0], 10);
  157.     top_output(OUT_SCREEN, getlang("CDTotal"), outnum[0],
  158.                user.cybercash == 1 ? getlang("CDSingular") :
  159.                                      getlang("CDPlural"));
  160.     return;
  161.     }
  162. /* PROFILE command (enter the profile editor). */
  163. if (checkcmdmatch(get_word(0), getlang("CmdsProfile")) > 0 &&
  164.     numwds == 1)
  165.     {
  166.     node->task |= TASK_EDITING;
  167.     save_node_data(od_control.od_node, node);
  168.     dispatch_message(MSG_INEDITOR, user.handle, -1, 0, 0);
  169.     cmi_busy();
  170.     profile_editor();
  171.     cmi_unbusy();
  172.     node->task = node->task & (0xFF - TASK_EDITING);
  173.     save_node_data(od_control.od_node, node);
  174.     dispatch_message(MSG_OUTEDITOR, user.handle, -1, 0, 0);
  175.     return;
  176.     }
  177. /* BIO command (enter the biography editor). */
  178. if (checkcmdmatch(get_word(0), getlang("CmdsBio")) > 0 &&
  179.     numwds == 1)
  180.     {
  181.     node->task |= TASK_EDITING;
  182.     save_node_data(od_control.od_node, node);
  183.     dispatch_message(MSG_INBIOEDITOR, user.handle, -1, 0, 0);
  184.     cmi_busy();
  185.     bioeditor();
  186.     cmi_unbusy();
  187.     node->task = node->task & (0xFF - TASK_EDITING);
  188.     save_node_data(od_control.od_node, node);
  189.     dispatch_message(MSG_OUTBIOEDITOR, user.handle, -1, 0, 0);
  190.     return;
  191.     }
  192. /* LOOKUP command (view a user's biography. */
  193. if (checkcmdmatch(get_word(0), getlang("CmdsLookUp")) > 0)
  194.     {
  195. /* Old-style (pre-bio) lookup that showed all users. */
  196. /*    if (numwds == 1)
  197.         {
  198.         lookup("\0");
  199.         return;
  200.         }
  201.     lookup(&word_str[word_pos[1]]);*/
  202.     /* LOOKUP needs a user name. */
  203.     if (numwds == 1)
  204.         {
  205.         show_helpfile("HELPLKUP");
  206.         return;
  207.         }
  208.     if (displaybio(&word_str[word_pos[1]]))
  209.         {
  210.         top_output(OUT_SCREEN, getlang("LookUpSuffix"));
  211.         }
  212.     return;
  213.     }
  214. /* USERLIST command (show list of all TOP users). */
  215. if (checkcmdmatch(get_word(0), getlang("CmdsUserList")) > 0)
  216.     {
  217.     userlist();
  218.     return;
  219.     }
  220. /* /LOGOFF command (quit TOP and hang up immediately). */
  221. if (checkcmdmatch(get_word(0), getlang("CmdsLogOff")) > 0 &&
  222.     numwds == 1)
  223.     {
  224.     top_output(OUT_SCREEN, getlang("DirectLogOffMsg"));
  225.     dispatch_message(MSG_EXIT, user.xmessage, -1, 0, 0);
  226.     unregister_node(FALSE);
  227.     od_exit(8, TRUE);
  228.     return;
  229.     }
  230. /* CHAT command (enter private chat mode). */
  231. if (checkcmdmatch(get_word(0), getlang("CmdsPrivChat")) > 0)
  232.     {
  233.     /* CHAT needs a name. */
  234.     if (numwds > 1)
  235.         {
  236.         /* Determine the node of the user to chat with. */
  237.         sendto = find_node_from_name(tmpstr, tmphand,
  238.                                      &word_str[word_pos[1]]);
  239.  
  240.         if (sendto == -1)
  241.             {
  242.             top_output(OUT_SCREEN, getlang("NotLoggedIn"), tmphand);
  243.             }
  244.         if (sendto == -2)
  245.             {
  246.             top_output(OUT_SCREEN, getlang("NotSpecific"), tmphand);
  247.             }
  248.         if (sendto == -3)
  249.             {
  250.             top_output(OUT_SCREEN, getlang("HasForgotYou"),
  251.                        handles[lastsendtonode].string);
  252.             }
  253.         /* CHAT can be done across channels. */
  254.         if (sendto == -4)
  255.             {
  256.             sendto = lastsendtonode;
  257.             }
  258.         /* Can't chat with yourself (it would be a nightmare technically). */
  259.         if (sendto == od_control.od_node)
  260.             {
  261.             top_output(OUT_SCREEN, getlang("CantDoCmdToSelf"));
  262.             return;
  263.             }
  264.         if (sendto >= 0)
  265.             {
  266.             if (privchatin >= 0 && privchatin != sendto)
  267.                 {
  268.                 /* If somebody else is waiting to chat with this node,
  269.                    the user can't request a chat. */
  270.                 top_output(OUT_SCREEN, getlang("PrivChatCantReq1"),
  271.                            handles[privchatin].string);
  272.                 return;
  273.                 }
  274.             if (privchatout >= 0)
  275.                 {
  276.                 /* If we've already requested to chat with somebody, we
  277.                    can't request another chat. */
  278.                 top_output(OUT_SCREEN, getlang("PrivChatCantReq2"),
  279.                            handles[privchatout].string);
  280.                 return;
  281.                 }
  282.  
  283.             if (privchatin == sendto)
  284.                 {
  285.                 /* Answer a chat request from another node, which engages
  286.                    private chat mode. */
  287.  
  288.                 /* Notify everybody else in the channel that we are going
  289.                    into private chat mode. */
  290.                 dispatch_message(MSG_INPRIVCHAT, user.handle, -1, 0, 0);
  291.                 /* Acknowledge the private chat. */
  292.                 msgsendglobal = 1;
  293.                 dispatch_message(MSG_WANTSPRIVCHAT, user.handle,
  294.                                  privchatin, 1, 0);
  295.                 node->task |= TASK_PRIVATECHAT;
  296.                 save_node_data(od_control.od_node, node);
  297.                 cmi_busy();
  298.                 privatechat(privchatin);
  299.                 cmi_unbusy();
  300.                 node->task = node->task & (0xFF - TASK_PRIVATECHAT);
  301.                 save_node_data(od_control.od_node, node);
  302.                 dispatch_message(MSG_OUTPRIVCHAT, user.handle, -1, 0, 0);
  303.                 }
  304.             else
  305.                 {
  306.                 /* We are sending a new request to the other node. */
  307.                 msgsendglobal = 1;
  308.                 dispatch_message(MSG_WANTSPRIVCHAT, user.handle,
  309.                                  sendto, 1, 0);
  310.                 top_output(OUT_SCREEN, getlang("PrivChatReqOK"),
  311.                            handles[sendto].string);
  312.                 privchatout = sendto;
  313.                 }
  314.             }
  315.         return;
  316.         }
  317.     }
  318. /* DENYCHAT command (denies a user's private chat request. */
  319. if (checkcmdmatch(get_word(0), getlang("CmdsPrivDenyChat")) > 0 &&
  320.     numwds == 1)
  321.     {
  322.     if (privchatin >= 0)
  323.         {
  324.         /* Deny a request if we have one. */
  325.         msgsendglobal = 1;
  326.         dispatch_message(MSG_DENYPRIVCHAT, user.handle, privchatin, 1, 0);
  327.         top_output(OUT_SCREEN, getlang("PrivChatDenyOK"),
  328.                    handles[privchatin].string);
  329.         privchatin = -1;
  330.         }
  331.     else
  332.         {
  333.         /* No request to deny. */
  334.         top_output(OUT_SCREEN, getlang("PrivChatCantDeny"));
  335.         }
  336.     return;
  337.     }
  338. /* NODES command (show who's on the entire BBS). */
  339. if (checkcmdmatch(get_word(0), getlang("CmdsNodes")) > 0 &&
  340.     numwds == 1)
  341.     {
  342.     /* This command only works if BBS interfacing is on. */
  343.     if (cfg.bbstype == BBS_UNKNOWN)
  344.         {
  345.         top_output(OUT_SCREEN, getlang("CmdNotAvail"));
  346.         return;
  347.         }
  348.     bbs_useron(TRUE);
  349.     return;
  350.     }
  351. /* PAGE command (send a message to a user elsewhere on the BBS). */
  352. if (checkcmdmatch(get_word(0), getlang("CmdsPage")) > 0)
  353.     {
  354.     XINT pnode = -1; /* Node to page. */
  355.     char *pmsg = NULL; /* Text to page the node with. */
  356.  
  357.     /* This command only works if BBS interfacing is on. */
  358.     if (cfg.bbstype == BBS_UNKNOWN)
  359.         {
  360.         top_output(OUT_SCREEN, getlang("CmdNotAvail"));
  361.         return;
  362.         }
  363.     /* The user specified the node number with the command. */
  364.     if (numwds > 1)
  365.         {
  366.         pnode = atoi(get_word(1));
  367.         if (pnode < 1)
  368.             {
  369.             itoa(cfg.maxnodes - 1, outnum[0], 10);
  370.             top_output(OUT_SCREEN, getlang("InvalidNode"), outnum[0]);
  371.             return;
  372.             }
  373.         }
  374.     /* The user specified text with the command. */
  375.     if (numwds > 2)
  376.         {
  377.         pmsg = &word_str[word_pos[2]];
  378.         }
  379.     bbs_page(pnode, pmsg);
  380.     return;
  381.     }
  382. /* FORGET command (ignores a user). */
  383. if (cfg.allowforgetting && user.security >= cfg.forgetsec &&
  384.     checkcmdmatch(get_word(0), getlang("CmdsForget")) > 0)
  385.     {
  386.     /* FORGET needs a name. */
  387.     if (numwds > 1)
  388.         {
  389.         node_idx_typ fgtchk; /* Data for node to forget. */
  390.  
  391.         /* Find node of user to forget. */
  392.         sendto = find_node_from_name(tmpstr, tmphand,
  393.                                      &word_str[word_pos[1]]);
  394.  
  395.         /* FORGET is channel-independent and does not care if the user
  396.            has already forgotten us. */
  397.         if (sendto == -3 || sendto == -4)
  398.             {
  399.             sendto = lastsendtonode;
  400.             }
  401.  
  402.         if (sendto == -1)
  403.             {
  404.             top_output(OUT_SCREEN, getlang("NotLoggedIn"), tmphand);
  405.             }
  406.         if (sendto == -2)
  407.             {
  408.             top_output(OUT_SCREEN, getlang("NotSpecific"), tmphand);
  409.             }
  410.         /* Forgetting yourself was causing too many technical problems
  411.            so it is restricted to other users. */
  412.         if (sendto == od_control.od_node)
  413.             {
  414.             top_output(OUT_SCREEN, getlang("CantDoCmdToSelf"));
  415.             return;
  416.             }
  417.         get_node_data(sendto, &fgtchk);
  418.         /* Can't forget a user with sysop security. */
  419.         if (fgtchk.security >= cfg.sysopsec)
  420.             {
  421.             top_output(OUT_SCREEN, getlang("CantDoCmdToSysop"));
  422.             return;
  423.             }
  424.         if (sendto >= 0)
  425.             {
  426.             forgetstatus[sendto] |= FGT_FORGOTTEN;
  427.             msgsendglobal = 1;
  428.             dispatch_message(MSG_FORGET, "\0", sendto, 1, 0);
  429.             top_output(OUT_SCREEN, getlang("Forgotten"),
  430.                        handles[sendto].string);
  431.             }
  432.         return;
  433.         }
  434.     }
  435. /* REMEMBER command (undoes a FORGET command). */
  436. if (cfg.allowforgetting && user.security >= cfg.forgetsec &&
  437.     checkcmdmatch(get_word(0), getlang("CmdsRemember")) > 0)
  438.     {
  439.     /* Find node of user to forget. */
  440.     if (numwds > 1)
  441.         {
  442.         sendto = find_node_from_name(tmpstr, tmphand,
  443.                                      &word_str[word_pos[1]]);
  444.  
  445.         /* REMEMBER is channel-independent and does not care if the user
  446.            has forgotten us. */
  447.         if (sendto == -3 || sendto == -4)
  448.             {
  449.             sendto = lastsendtonode;
  450.             }
  451.  
  452.         if (sendto == -1)
  453.             {
  454.             top_output(OUT_SCREEN, getlang("NotLoggedIn"), tmphand);
  455.             }
  456.         if (sendto == -2)
  457.             {
  458.             top_output(OUT_SCREEN, getlang("NotSpecific"), tmphand);
  459.             }
  460.         /* Technically remembering yourself does not cause any problems
  461.            (even though forgetting yourself does) but for consistency it is
  462.            not allowed. */
  463.         if (sendto == od_control.od_node)
  464.             {
  465.             top_output(OUT_SCREEN, getlang("CantDoCmdToSelf"));
  466.             return;
  467.             }
  468.         if (sendto >= 0)
  469.             {
  470.             forgetstatus[sendto] &= (255 - FGT_FORGOTTEN);
  471.             msgsendglobal = 1;
  472.             dispatch_message(MSG_REMEMBER, "\0", sendto, 1, 0);
  473.             top_output(OUT_SCREEN, getlang("Remembered"),
  474.                        handles[sendto].string);
  475.             }
  476.         return;
  477.         }
  478.     }
  479. /* User hit ENTER without typing any text. */
  480. if (string[0] == 0 || numwds == 0)
  481.     {
  482.     /* Show the quick list of who's online and the short help. */
  483.     channelsummary();
  484.     return;
  485.     }
  486. /* JOIN command (changes the user's current channel. */
  487. if (checkcmdmatch(get_word(0), getlang("CmdsJoin")) > 0)
  488.     {
  489.     unsigned long tchan; /* Channel to join. */
  490.     long tch; /* Channel record number. */
  491.  
  492.     if (numwds > 1)
  493.         {
  494.         /* Check the channel name (if one was used) is valid. */
  495.         if ((tchan = checkchannelname(&word_str[word_pos[1]])) > 0)
  496.             {
  497.             /* The name is valid. */
  498.  
  499.             /* Get the data from CHANIDX.TCH. */
  500.             tch = findchannelrec(tchan);
  501.             if (tch > -1L)
  502.                 {
  503.                 /* Data was found. */
  504.  
  505.                 if (user.security < chan[tch].minsec ||
  506.                     user.security > chan[tch].maxsec)
  507.                     {
  508.                     top_output(OUT_SCREEN, getlang("BadChannelSec"));
  509.                     }
  510.                 else
  511.                     {
  512.                     /* Leave the current channel. */
  513.                     res = cmi_unjoin(curchannel);
  514.                     if (res != CMI_OKAY)
  515.                         {
  516.                         top_output(OUT_SCREEN, getlang("UnJoinError"));
  517.                         }
  518.                     /* Join the new channel. */
  519.                     res = cmi_join(tchan);
  520.                     if (res == CMIERR_BANNED)
  521.                         {
  522.                         top_output(OUT_SCREEN, getlang("Banned"));
  523.                         }
  524.                     if (res == CMIERR_NOINV)
  525.                         {
  526.                         top_output(OUT_SCREEN, getlang("NotInvited"));
  527.                         }
  528.                     if (res != CMI_OKAY && res != CMIERR_BANNED &&
  529.                         res != CMIERR_NOINV)
  530.                         {
  531.                         top_output(OUT_SCREEN, getlang("JoinError"));
  532.                         }
  533.                     if (res == CMI_OKAY)
  534.                         {
  535.                         /* The join was successful. */
  536.                         if (tchan > 0UL && tchan < 4000000000UL)
  537.                             {
  538.                             top_output(OUT_SCREEN, getlang("NowInChannel"),
  539.                                        channelname(tchan));
  540.                             }
  541.                         if (tchan >= 4001000000UL)
  542.                             {
  543.                             top_output(OUT_SCREEN, getlang("NowInConference"),
  544.                                        channelname(tchan));
  545.                             }
  546.                         dispatch_message(MSG_OUTCHANNEL, "\0", -1, 0, 0);
  547.                         curchannel = tchan;
  548.                         node->channel = curchannel;
  549.                         save_node_data(od_control.od_node, node);
  550.                         dispatch_message(MSG_INCHANNEL, "\0", -1, 0, 0);
  551.                         channelsummary();
  552.                         }
  553.                     else
  554.                         {
  555.                         /* Rejoin the previous channel since we're not
  556.                            allowed in the new one. */
  557.                         res = cmi_join(curchannel);
  558.                         if (res != CMI_OKAY)
  559.                             {
  560.                             top_output(OUT_SCREEN, getlang("CantReJoin"));
  561.                             od_exit(230, FALSE);
  562.                             }
  563.                         }
  564.                     }
  565.                 }
  566.             else
  567.                 {
  568.                 /* No data was found.  Currently the only difference if this
  569.                    occurs is that the security is not checked, but this may
  570.                    change so the entire procedure is duplicated. */
  571.  
  572.                 /* Leave the current channel. */
  573.                 res = cmi_unjoin(curchannel);
  574.                 if (res != CMI_OKAY)
  575.                     {
  576.                     top_output(OUT_SCREEN, getlang("UnJoinError"));
  577.                     }
  578.                 /* Join the new channel. */
  579.                 res = cmi_join(tchan);
  580.                 if (res == CMIERR_BANNED)
  581.                     {
  582.                     top_output(OUT_SCREEN, getlang("Banned"));
  583.                     }
  584.                 if (res == CMIERR_NOINV)
  585.                     {
  586.                     top_output(OUT_SCREEN, getlang("NotInvited"));
  587.                     }
  588.                 if (res != CMI_OKAY && res != CMIERR_BANNED &&
  589.                     res != CMIERR_NOINV)
  590.                     {
  591.                     top_output(OUT_SCREEN, getlang("JoinError"));
  592.                     }
  593.                 if (res == CMI_OKAY)
  594.                     {
  595.                     /* The join was sucessful. */
  596.                     if (tchan > 0UL && tchan < 4000000000UL)
  597.                         {
  598.                         top_output(OUT_SCREEN, getlang("NowInChannel"),
  599.                                    channelname(tchan));
  600.                         }
  601.                     if (tchan >= 4001000000UL)
  602.                         {
  603.                         top_output(OUT_SCREEN, getlang("NowInConference"),
  604.                                    channelname(tchan));
  605.                         }
  606.                     dispatch_message(MSG_OUTCHANNEL, "\0", -1, 0, 0);
  607.                     curchannel = tchan;
  608.                     node->channel = curchannel;
  609.                     save_node_data(od_control.od_node, node);
  610.                     dispatch_message(MSG_INCHANNEL, "\0", -1, 0, 0);
  611.                     channelsummary();
  612.                     }
  613.                 else
  614.                     {
  615.                     /* Rejoin the old channel since we're not allowed in the
  616.                        new one. */
  617.                     res = cmi_join(curchannel);
  618.                     if (res != CMI_OKAY)
  619.                         {
  620.                         top_output(OUT_SCREEN, getlang("CantReJoin"));
  621.                         od_exit(230, FALSE);
  622.                         }
  623.                     }
  624.                 }
  625.             }
  626.         else
  627.             {
  628.             /* The name was invalid. */
  629.  
  630.             /* If the second word (the channel to join) is all digits, it
  631.                is not considered a name. */
  632.             for (z = 0; z < strlen(&word_str[word_pos[1]]); z++)
  633.                 {
  634.                 if (!isdigit(word_str[word_pos[1] + z]))
  635.                     {
  636.                     z = -1;
  637.                     break;
  638.                     }
  639.                 }
  640.  
  641.             /* Convert the string to a number. */
  642.             tchan = strtoul(&word_str[word_pos[1]], NULL, 10);
  643.  
  644.             /* Join the channel by number. */
  645.             if (((tchan > 0 && tchan < 4000000000UL) ||
  646.                 /* Sysops may join channel 0 for global announcements. */
  647.                 (tchan == 0 && user.security >= cfg.sysopsec)) &&
  648.                 z != -1)
  649.                 {
  650.                 /* Leave the current channel. */
  651.                 res = cmi_unjoin(curchannel);
  652.                 if (res != CMI_OKAY)
  653.                     {
  654.                     top_output(OUT_SCREEN, getlang("UnJoinError"));
  655.                     }
  656.                 /* Join the new channel. */
  657.                 res = cmi_join(tchan);
  658.                 if (res == CMIERR_BANNED)
  659.                     {
  660.                     top_output(OUT_SCREEN, getlang("Banned"));
  661.                     }
  662.                 if (res == CMIERR_NOINV)
  663.                     {
  664.                     top_output(OUT_SCREEN, getlang("NotInvited"));
  665.                     }
  666.                 if (res != CMI_OKAY && res != CMIERR_BANNED &&
  667.                     res != CMIERR_NOINV)
  668.                     {
  669.                     top_output(OUT_SCREEN, getlang("JoinError"));
  670.                     }
  671.                 if (res == CMI_OKAY)
  672.                     {
  673.                     /* The join was successful. */
  674.                     top_output(OUT_SCREEN, getlang("NowInChannel"),
  675.                                channelname(tchan));
  676.                     dispatch_message(MSG_OUTCHANNEL, "\0", -1, 0, 0);
  677.                     curchannel = tchan;
  678.                     node->channel = curchannel;
  679.                     save_node_data(od_control.od_node, node);
  680.                     dispatch_message(MSG_INCHANNEL, "\0", -1, 0, 0);
  681.                     channelsummary();
  682.                     }
  683.                 else
  684.                     {
  685.                     /* Rejoin the old channel as we are not allowed in
  686.                        the new one. */
  687.                     res = cmi_join(curchannel);
  688.                     if (res != CMI_OKAY)
  689.                         {
  690.                         top_output(OUT_SCREEN, getlang("CantReJoin"));
  691.                         od_exit(230, FALSE);
  692.                         }
  693.                     }
  694.                 }
  695.             else
  696.                 {
  697.                 /* The name is invalid and it was not determined to be a
  698.                    number, so see if it is the name of a user to join their
  699.                    personal channel. */
  700.                 sendto = find_node_from_name(tmpstr, tmphand,
  701.                                              &word_str[word_pos[1]]);
  702.                 /* Obviously, the JOIN command is channel-independent. */
  703.                 if (sendto == -4)
  704.                     {
  705.                     sendto = lastsendtonode;
  706.                     }
  707.                 if (sendto >= 0)
  708.                     {
  709.                     /* A user's name was found so join their personal
  710.                        channel. */
  711.                     tchan = (long) sendto + 4000000000UL;
  712.  
  713.                     /* Leave the current channel. */
  714.                     res = cmi_unjoin(curchannel);
  715.                     if (res != CMI_OKAY)
  716.                         {
  717.                         top_output(OUT_SCREEN, getlang("UnJoinError"));
  718.                         }
  719.                     /* Join the new one. */
  720.                     res = cmi_join(tchan);
  721.                     if (res == CMIERR_BANNED)
  722.                         {
  723.                         top_output(OUT_SCREEN, getlang("Banned"));
  724.                         }
  725.                     if (res == CMIERR_NOINV)
  726.                         {
  727.                         top_output(OUT_SCREEN, getlang("NotInvited"));
  728.                         }
  729.                     if (res != CMI_OKAY && res != CMIERR_BANNED &&
  730.                         res != CMIERR_NOINV)
  731.                         {
  732.                         top_output(OUT_SCREEN, getlang("JoinError"));
  733.                         }
  734.                     if (res == CMI_OKAY)
  735.                         {
  736.                         /* The join was sucessful. */
  737.                         top_output(OUT_SCREEN, getlang("NowInUserChannel"),
  738.                                    channelname(tchan));
  739.                         dispatch_message(MSG_OUTCHANNEL, "\0", -1, 0, 0);
  740.                         curchannel = tchan;
  741.                         node->channel = curchannel;
  742.                         save_node_data(od_control.od_node, node);
  743.                         dispatch_message(MSG_INCHANNEL, "\0", -1, 0, 0);
  744.                         channelsummary();
  745.                         }
  746.                     else
  747.                         {
  748.                         /* Rejoin the old channel as we're not allowed in
  749.                            the new one. */
  750.                         res = cmi_join(curchannel);
  751.                         if (res != CMI_OKAY)
  752.                             {
  753.                             top_output(OUT_SCREEN, getlang("CantReJoin"));
  754.                             od_exit(230, FALSE);
  755.                             }
  756.                         }
  757.                     }
  758.                 else
  759.                     {
  760.                     /* Invalid channel number/name. */
  761.                     top_output(OUT_SCREEN, getlang("BadChannelName"));
  762.                     }
  763.                 }
  764.             }
  765.         return;
  766.         }
  767.     }
  768. /* CONFLIST command (list conferences). */
  769. if (checkcmdmatch(get_word(0), getlang("CmdsConfList")) > 0 &&
  770.     numwds == 1)
  771.     {
  772.     list_channels();
  773.     return;
  774.     }
  775. /* MODERATOR multi-word command. */
  776. if (checkcmdmatch(get_word(0), getlang("CmdsModerator")) > 0)
  777.     {
  778.     mod_proc();
  779.     return;
  780.     }
  781. /* SYSOP multi-word command. */
  782. if (checkcmdmatch(get_word(0), getlang("CmdsSysop")) > 0 &&
  783.     user.security >= cfg.sysopsec)
  784.     {
  785.     sysop_proc();
  786.     return;
  787.     }
  788. /* CHANGE multi-word command. */
  789. if (checkcmdmatch(get_word(0), getlang("CmdsChange")) > 0)
  790.     {
  791.     change_proc();
  792.     return;
  793.     }
  794. /* General action. */
  795. if (!(user.pref2 & PREF2_ACTIONSOFF) && cfg.allowgas &&
  796.     checkcmdmatch(get_word(0), getlang("CmdsGA")) > 0)
  797.     {
  798.     if (user.security < cfg.actionusesec)
  799.         {
  800.         top_output(OUT_SCREEN, getlang("NoAccActUse"));
  801.         return;
  802.         }
  803.     /* GAs need text after the command. */
  804.     if (numwds > 1)
  805.         {
  806.         top_output(OUT_SCREEN, getlang("GASentPrefix"));
  807.         dispatch_message(MSG_GA, &word_str[word_pos[1]], -1, 0, echoga);
  808.         if (msgsent)
  809.             {
  810.             top_output(OUT_SCREEN, getlang("GASent"));
  811.             }
  812.         return;
  813.         }
  814.     top_output(OUT_SCREEN, getlang("GANotSentPrefix"));
  815.     if (msgsent)
  816.         {
  817.         top_output(OUT_SCREEN, getlang("GANotSent"));
  818.         }
  819.     return;
  820.     }
  821. /* Posessive general action. */
  822. if (!(user.pref2 & PREF2_ACTIONSOFF) && cfg.allowgas &&
  823.     checkcmdmatch(get_word(0), getlang("CmdsGA2")) > 0)
  824.     {
  825.     /* This command is treated identically to a normal GA except for the
  826.        message number sent to other nodes. */
  827.  
  828.     if (user.security < cfg.actionusesec)
  829.         {
  830.         top_output(OUT_SCREEN, getlang("NoAccActUse"));
  831.         return;
  832.         }
  833.     if (numwds > 1)
  834.         {
  835.         top_output(OUT_SCREEN, getlang("GASentPrefix"));
  836.         dispatch_message(MSG_GA2, &word_str[word_pos[1]], -1, 0, echoga);
  837.         if (msgsent)
  838.             {
  839.             top_output(OUT_SCREEN, getlang("GASent"));
  840.             }
  841.         return;
  842.         }
  843.     top_output(OUT_SCREEN, getlang("GANotSentPrefix"));
  844.     if (msgsent)
  845.         {
  846.         top_output(OUT_SCREEN, getlang("GANotSent"));
  847.         }
  848.     return;
  849.     }
  850.  
  851. /* Game multi-word commands, not used at this time. */
  852. /*//|if (checkcmdmatch(get_word(0), getlang("CmdsSlots")))
  853.     {
  854.     slots_game();
  855.     return;
  856.     }
  857. if (checkcmdmatch(get_word(0), getlang("CmdsPoker")))
  858.     {
  859.     poker_game(numwds);
  860.     return;
  861.     }
  862. if (checkcmdmatch(get_word(0), getlang("CmdsMatchGame")))
  863.     {
  864.     matchgame();
  865.     return;
  866.     }*///|
  867.  
  868. /* Spawn commands, not used at this time. */
  869. /*if (check_spawn_cmds(numwds))
  870.     {
  871.     return;
  872.     }*/
  873.  
  874. /* Whispers (WHISPER TO or /). */
  875. if (cfg.allowprivmsgs &&
  876.     /* Check both words of the long form and the single character of the
  877.        short form. */
  878.     ((checkcmdmatch(get_word(0), getlang("CmdsWhisperLong1")) &&
  879.      checkcmdmatch(get_word(1), getlang("CmdsWhisperLong2"))) ||
  880.      get_word_char(0, 0) == getlangchar("WhisperShortChar", 0)))
  881.     {
  882.     if (user.security < cfg.privmessagesec)
  883.         {
  884.         top_output(OUT_SCREEN, getlang("NoAccPrivMsg"));
  885.         return;
  886.         }
  887.  
  888.     if (get_word_char(0, 0) == getlangchar("WhisperShortChar", 0))
  889.         {
  890.         /* Short form was used, so the length of the command is one (a
  891.            single character). */
  892.         cmdlen = 1;
  893.         /* Test if only the command letter was specified. */
  894.         if (strlen(get_word(0)) == 1)
  895.             {
  896.             cmdlen = -1;
  897.             }
  898.         }
  899.     else
  900.         {
  901.         /* Long form was used, so the command length is the length of the
  902.            two command words (usually WHISPER TO). */
  903.         cmdlen = word_pos[2];
  904.         /* Test if only the two command words were specified. */
  905.         if (numwds < 3)
  906.             {
  907.             cmdlen = -1;
  908.             }
  909.         }
  910.  
  911.     if (cmdlen >= 0)
  912.         {
  913.         /* Determine which node to send the whisper to. */
  914.         sendto = find_node_from_name(tmpstr, tmphand, &string[cmdlen]);
  915.  
  916.         /* Don't send if no text was specified (i.e. just a name). */
  917.         if ((tmpstr[0] == '\0' || tmpstr[1] == '\0') && sendto >= 0)
  918.             {
  919.             cmdlen = -1;
  920.             }
  921.  
  922.         if (cmdlen >= 0)
  923.             {
  924.             if (sendto == -1)
  925.                 {
  926.                 top_output(OUT_SCREEN, getlang("NotLoggedIn"), tmphand);
  927.                 }
  928.             if (sendto == -2)
  929.                 {
  930.                 top_output(OUT_SCREEN, getlang("NotSpecific"), tmphand);
  931.                 }
  932.             if (sendto == -3)
  933.                 {
  934.                 top_output(OUT_SCREEN, getlang("HasForgotYou"),
  935.                            handles[lastsendtonode].string);
  936.                 }
  937.             if (sendto == -4)
  938.                 {
  939.                 top_output(OUT_SCREEN, getlang("NotInYourChannel"),
  940.                            handles[lastsendtonode].string);
  941.                 }
  942.             if (sendto >= 0)
  943.                 {
  944.                 /* Send the whisper. */
  945.                 top_output(OUT_SCREEN, getlang("WhisperSentPrefix"));
  946.                 dispatch_message(MSG_WHISPER, spacecheck(tmpstr), sendto,
  947.                                  1, 0);
  948.                 if (msgsent)
  949.                     {
  950.                     top_output(OUT_SCREEN, getlang("WhisperSent"),
  951.                                handles[sendto].string);
  952.                     }
  953.                 }
  954.             return;
  955.             }
  956.         }
  957.  
  958.     /* Not enough information was specified. */
  959.     top_output(OUT_SCREEN, getlang("WhisperNotSentPref"));
  960.     if (msgsent)
  961.         {
  962.         top_output(OUT_SCREEN, getlang("WhisperNotSent"));
  963.         }
  964.     return;
  965.     }
  966. /* Directed messages. */
  967. if ( ((checkcmdmatch(get_word(0), getlang("CmdsDirectedLong1")) &&
  968.      checkcmdmatch(get_word(1), getlang("CmdsDirectedLong2"))) ||
  969.      get_word_char(0, 0) == getlangchar("DirectedShortChar", 0)))
  970.     {
  971.     /* Directed messages are handled identically to whispers except for the
  972.        commands, the message sent to other nodes, and the language items
  973.        used. */
  974.  
  975.     if (get_word_char(0, 0) == getlangchar("DirectedShortChar", 0))
  976.         {
  977.         cmdlen = 1;
  978.         if (strlen(get_word(0)) == 1)
  979.             {
  980.             cmdlen = -1;
  981.             }
  982.         }
  983.     else
  984.         {
  985.         cmdlen = word_pos[2];
  986.         if (numwds < 3)
  987.             {
  988.             cmdlen = -1;
  989.             }
  990.         }
  991.  
  992.     if (cmdlen >= 0)
  993.         {
  994.         sendto = find_node_from_name(tmpstr, tmphand, &string[cmdlen]);
  995.         if ((tmpstr[0] == '\0' || tmpstr[1] == '\0') && sendto >= 0)
  996.             {
  997.             cmdlen = -1;
  998.             }
  999.  
  1000.         if (cmdlen >= 0)
  1001.             {
  1002.             if (sendto == -1)
  1003.                 {
  1004.                 top_output(OUT_SCREEN, getlang("NotLoggedIn"), tmphand);
  1005.                 }
  1006.             if (sendto == -2)
  1007.                 {
  1008.                 top_output(OUT_SCREEN, getlang("NotSpecific"), tmphand);
  1009.                 }
  1010.             if (sendto == -3)
  1011.                 {
  1012.                 top_output(OUT_SCREEN, getlang("HasForgotYou"),
  1013.                            handles[lastsendtonode].string);
  1014.                 }
  1015.             if (sendto == -4)
  1016.                 {
  1017.                 top_output(OUT_SCREEN, getlang("NotInYourChannel"),
  1018.                            handles[lastsendtonode].string);
  1019.                 }
  1020.             if (sendto >= 0)
  1021.                 {
  1022.                 top_output(OUT_SCREEN, getlang("DirectedSentPrefix"));
  1023.                 dispatch_message(MSG_DIRECTED, spacecheck(tmpstr), sendto,
  1024.                                  0, user.pref2 & PREF2_ECHOOWNTEXT);
  1025.                 if (msgsent)
  1026.                     {
  1027.                     top_output(OUT_SCREEN, getlang("DirectedSent"),
  1028.                                handles[sendto].string);
  1029.                     }
  1030.                 }
  1031.             return;
  1032.             }
  1033.         }
  1034.     top_output(OUT_SCREEN, getlang("DirectNotSentPref"));
  1035.     if (msgsent)
  1036.         {
  1037.         top_output(OUT_SCREEN, getlang("DirectedNotSent"));
  1038.         }
  1039.     return;
  1040.     }
  1041.  
  1042. /* Old-style (single list) action processor. */
  1043. /*load_action_verbs();
  1044. for (z = 0; z < numactions && !auflg && !cfg.allowactions; z++)
  1045.     {
  1046.     if (!stricmp(verbs[z].string, get_word(0)) &&
  1047.         verbs[z].string[0])
  1048.         {
  1049.         process_action(z, numwds, string);
  1050.         z = numactions;
  1051.         top_output(OUT_SCREEN, getlang("ActionUseSuffix"));
  1052.         auflg = 1;
  1053.         }
  1054.     }
  1055. for (z = 0; z < 4 && !auflg && cfg.allowactions; z++)
  1056.     {
  1057.     if (!stricmp(user.persact[z].verb, get_word(0)) &&
  1058.         user.persact[z].verb[0])
  1059.         {
  1060.         process_action(-(z + 1), numwds, string);
  1061.         z = 1000;
  1062.         top_output(OUT_SCREEN, getlang("ActionUseSuffix"));
  1063.         auflg = 1;
  1064.         }
  1065.     }*/
  1066.  
  1067. /* Check if the user used an action. */
  1068. if (cfg.allowactions && !(user.pref2 & PREF2_ACTIONSOFF) &&
  1069.     user.security >= cfg.actionusesec)
  1070.     {
  1071.     if (action_check(numwds))
  1072.         {
  1073.         return;
  1074.         }
  1075.     }
  1076.  
  1077. /* Normal text. */
  1078. if (user.security < cfg.talksec)
  1079.     {
  1080.     top_output(OUT_SCREEN, getlang("NoAccTalk"));
  1081.     return;
  1082.     }
  1083. dispatch_message(MSG_TEXT, string, priv, 0,
  1084.                  user.pref2 & PREF2_ECHOOWNTEXT);
  1085. top_output(OUT_SCREEN, getlang("MsgSentPrefix"));
  1086. if (msgsent)
  1087.     {
  1088.     top_output(OUT_SCREEN, getlang("MsgSent"));
  1089.     }
  1090.  
  1091. }
  1092.