home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / top2src.zip / ACTIONS.C next >
C/C++ Source or Header  |  2000-07-13  |  24KB  |  633 lines

  1. /******************************************************************************
  2. ACTIONS.C    Contains all functions relating to Actions.
  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 contains all action-related functions, including the loading,
  20. processing, and listing of actions.
  21. ******************************************************************************/
  22.  
  23. #include "top.h"
  24.  
  25. /* loadactions() - Loads all actions into memory.
  26.    Parameters:  None.
  27.    Returns:  TRUE if the actions were successfully loaded, FALSE if falure
  28.              occurred.
  29. */
  30. char loadactions(void)
  31.     {
  32.     unsigned XINT lad, lae; /* Counters. */
  33.     XINT actfil; /* File handle for loading actions. */
  34.     unsigned long ldat = 0, ltxt; /* File position trackers. */
  35.     unsigned char *memchk = NULL; /* Errorchecking pointer. */
  36.  
  37.     /* Allocate space for the pointer index. */
  38.     actfiles = calloc(numactfiles + 1, sizeof(action_file_typ XFAR *));
  39.     if (actfiles == NULL)
  40.         {
  41.         return 0;
  42.         }
  43.  
  44.     /* Allocate space for each file's header. */
  45.     for (lad = 0; lad <= numactfiles; lad++)
  46.         {
  47.         actfiles[lad] = malloc(sizeof(action_file_typ));
  48.         if (actfiles[lad] == NULL)
  49.             {
  50.             return 0;
  51.             }
  52.         }
  53.  
  54.     /* Prepare list #0 as the personal action list. */
  55.     strcpy(actfiles[0]->name, top_output(OUT_STRING,
  56.            getlang("PersActListDesc")));
  57.     // These next four should be configurable later.
  58.     actfiles[0]->minsec = 0;
  59.     actfiles[0]->maxsec = 0xFFFF;
  60.     actfiles[0]->minchannel = 0;
  61.     actfiles[0]->maxchannel = MAXCHANNEL;
  62.     actfiles[0]->numactions = 4;
  63.  
  64.     /* Read the header data for each action file.  This "first pass" allows
  65.        TOP to count the actions in each file. */
  66.     for (lad = 1; lad <= numactfiles; lad++)
  67.         {
  68.         strcpy(outbuf, cfg.topactpath);
  69.         strcat(outbuf, cfg.actfilenames[lad]);
  70.         strcat(outbuf, ".TAC");
  71.         actfil = sh_open(outbuf, O_RDWR | O_CREAT | O_BINARY,
  72.                          SH_DENYNONE, S_IREAD | S_IWRITE);
  73.         if (actfil == -1)
  74.             {
  75.             return 0;
  76.             }
  77.         lseek(actfil, 0, SEEK_SET);
  78.         read(actfil, actfiles[lad], sizeof(action_file_typ));
  79.         close(actfil);
  80.         }
  81.  
  82.     /* Allocate space for the actual action data.  First the master index
  83.        is allocated, followed by each list's index and actual space in turn.
  84.        This is where a lot of memory gets sucked up. */
  85.     actptrs = calloc(numactfiles + 1, sizeof(action_file_typ XFAR *));
  86.     if (actptrs == NULL)
  87.         {
  88.         return 0;
  89.         }
  90.     for (lad = 0; lad <= numactfiles; lad++)
  91.         {
  92.         actptrs[lad] = calloc(actfiles[lad]->numactions,
  93.                               sizeof(action_rec_typ XFAR *));
  94.         if (actptrs[lad] == NULL)
  95.             {
  96.             return 0;
  97.             }
  98.         for (lae = 0; lae < actfiles[lad]->numactions; lae++)
  99.             {
  100.             actptrs[lad][lae] = malloc(sizeof(action_rec_typ));
  101.             if (actptrs[lad][lae] == NULL)
  102.                 {
  103.                 return 0;
  104.                 }
  105.             }
  106.         }
  107.  
  108.     /* Load and process each action file. */
  109.     for (lad = 1; lad <= numactfiles; lad++)
  110.         {
  111.         /* Open the file. */
  112.         strcpy(outbuf, cfg.topactpath);
  113.         strcat(outbuf, cfg.actfilenames[lad]);
  114.         strcat(outbuf, ".TAC");
  115.         actfil = sh_open(outbuf, O_RDWR | O_CREAT | O_BINARY,
  116.                          SH_DENYNONE, S_IREAD | S_IWRITE);
  117.         if (!actfil)
  118.             {
  119.             return 0;
  120.             }
  121.  
  122.         /* ldat tracks the position in the file where the next data is to
  123.            be loaded from. */
  124.         ldat = actfiles[lad]->datstart;
  125.  
  126.         /* Load and process each action. */
  127.         for (lae = 0; lae < actfiles[lad]->numactions; lae++)
  128.             {
  129.             /* Load the data for the action. */
  130.             lseek(actfil, ldat, SEEK_SET);
  131.             read(actfil, &actptrs[lad][lae]->data, sizeof(action_data_typ));
  132.             ldat += (long) sizeof(action_data_typ);
  133.  
  134.             /* Allocate space for the strings in the action.  This is done
  135.                dynamically to save memory.  The redundant memchk pointer
  136.                simply saves typing for errorchecking. */
  137.             memchk = actptrs[lad][lae]->ptrs.responsetext =
  138.                 malloc(actptrs[lad][lae]->data.responselen + 1);
  139.             if (memchk == NULL)
  140.                 {
  141.                 close(actfil);
  142.                 return 0;
  143.                 }
  144.             memset(actptrs[lad][lae]->ptrs.responsetext, 0,
  145.                    actptrs[lad][lae]->data.responselen + 1);
  146.             memchk = actptrs[lad][lae]->ptrs.singulartext =
  147.                 malloc(actptrs[lad][lae]->data.singularlen + 1);
  148.             if (memchk == NULL)
  149.                 {
  150.                 close(actfil);
  151.                 return 0;
  152.                 }
  153.             memset(actptrs[lad][lae]->ptrs.singulartext, 0,
  154.                    actptrs[lad][lae]->data.singularlen + 1);
  155.             memchk = actptrs[lad][lae]->ptrs.pluraltext =
  156.                 malloc(actptrs[lad][lae]->data.plurallen + 1);
  157.             if (memchk == NULL)
  158.                 {
  159.                 close(actfil);
  160.                 return 0;
  161.                 }
  162.             memset(actptrs[lad][lae]->ptrs.pluraltext, 0,
  163.                    actptrs[lad][lae]->data.plurallen + 1);
  164.  
  165.             /* ltxt tracks the position in the file where the string text
  166.                is to be loaded from. */
  167.             ltxt = actfiles[lad]->txtstart + actptrs[lad][lae]->data.textofs;
  168.  
  169.             /* Read the text for the action. */
  170.             // Still need errs down here.
  171.             lseek(actfil, ltxt, SEEK_SET);
  172.             read(actfil, actptrs[lad][lae]->ptrs.responsetext,
  173.                  actptrs[lad][lae]->data.responselen);
  174.             ltxt += actptrs[lad][lae]->data.responselen;
  175.             lseek(actfil, ltxt, SEEK_SET);
  176.             read(actfil, actptrs[lad][lae]->ptrs.singulartext,
  177.                  actptrs[lad][lae]->data.singularlen);
  178.             ltxt += actptrs[lad][lae]->data.singularlen;
  179.             lseek(actfil, ltxt, SEEK_SET);
  180.             read(actfil, actptrs[lad][lae]->ptrs.pluraltext,
  181.                  actptrs[lad][lae]->data.plurallen);
  182.             ltxt += actptrs[lad][lae]->data.plurallen;
  183.             }
  184.         close(actfil);
  185.         }
  186.  
  187.     /* If the loop is completed in full then the action loading was done
  188.        successfully. */
  189.     return 1;
  190.     }
  191.  
  192. /* action_check() - Checks the input string to see if it is an action.
  193.    Parameters:  awords - The number of words in the input string.
  194.    Returns:  TRUE if an action was found and processed, FALSE if not.
  195.    Notes:  The string that is to be processed must first be parsed by the
  196.            split_string() function.
  197. */
  198. char action_check(XINT awords)
  199.     {
  200.     unsigned XINT acd, ace; /* Counters. */
  201.  
  202.     /* Grab the first word and check to make sure the action prefix is
  203.        present, if one is defined.  outbuf is used as a temporary storage
  204.        buffer. */
  205.     strcpy(outbuf, get_word(0));
  206.     if (cfg.actionprefix[0])
  207.         {
  208.         if (strnicmp(outbuf, cfg.actionprefix, strlen(cfg.actionprefix)))
  209.             {
  210.             return 0;
  211.             }
  212.         }
  213.  
  214.     /* Check each action in each list against the string. */
  215.     for (acd = 0; acd <= numactfiles; acd++)
  216.         {
  217.         for (ace = 0; ace < actfiles[acd]->numactions; ace++)
  218.             {
  219.             if (!stricmp(&outbuf[strlen(cfg.actionprefix)],
  220.                          actptrs[acd][ace]->data.verb))
  221.                 {
  222.                 if (user.security >= actfiles[acd]->minsec &&
  223.                     user.security <= actfiles[acd]->maxsec &&
  224.                     curchannel >= actfiles[acd]->minchannel &&
  225.                     curchannel <= actfiles[acd]->maxchannel)
  226.                     {
  227.                     action_do(acd, ace, awords, &word_str[word_pos[1]]);
  228.                     return 1;
  229.                     }
  230.                 }
  231.             }
  232.         }
  233.  
  234.     return 0;
  235.     }
  236.  
  237. /* action_do() - Parses an action.
  238.    Parameters:  lnum - List number the action is found in.
  239.                 anum - Number of the action within the list.
  240.                 dowords - Number of words in the input string.
  241.                 dostr - Remainder of the string, not including the verb.
  242.    Returns:  Nothing.
  243. */
  244. void action_do(unsigned XINT lnum, unsigned XINT anum,
  245.                XINT dowords, unsigned char *dostr)
  246.     {
  247.     char secret = 0, doecho = 1; /* Secret and Echo flags. */
  248.     XINT sendto = -1, msgtype = -1; /* Node to send to and Type of message. */
  249.     /* Output pointer, and temporary handle buffer. */
  250.     unsigned char *useptr = NULL, tmphand[256];
  251.     XINT res; /* Result code. */
  252.  
  253.     /* Verify that the type of action is one this version of TOP can handle. */
  254.     if (actptrs[lnum][anum]->data.type < 0 ||
  255.         actptrs[lnum][anum]->data.type > 1)
  256.         {
  257.         top_output(OUT_SCREEN, getlang("CantDoAction"));
  258.         od_log_write(top_output(OUT_STRING, getlang("LogCantDoAction"),
  259.                                 get_word(0)));
  260.         return;
  261.         }
  262.  
  263.     /* The msgextradata is only used for some types of actions so it is
  264.        cleared for safety. */
  265.     msgextradata = -1L;
  266.  
  267.     /* Process the action based on its type. */
  268.     switch(actptrs[lnum][anum]->data.type)
  269.         {
  270.         case ACT_NORMAL:
  271.             if (dowords == 1)
  272.                 {
  273.                 /* Handle the singular case. */
  274.                 useptr = actptrs[lnum][anum]->ptrs.singulartext;
  275.                 msgtype = MSG_ACTIONSIN;
  276.                 doecho = user.pref1 & PREF1_ECHOACTIONS;
  277.                 strcpy(outbuf, useptr);
  278.                 }
  279.             else
  280.                 {
  281.                 /* Handle the plural case. */
  282.                 useptr = actptrs[lnum][anum]->ptrs.pluraltext;
  283.                 msgtype = MSG_ACTIONPLU;
  284.                 doecho = user.pref1 & PREF1_ECHOACTIONS;
  285.                 if (checkcmdmatch(get_word(1), getlang("CmdsActionAll")))
  286.                     {
  287.                     /* Action was done to "all". */
  288.                     sendto = -2;
  289.                     }
  290.                 else
  291.                     {
  292.                     /* Determine who "receives" the action. */
  293.                     sendto = find_node_from_name(outbuf, tmphand,
  294.                                 dostr);
  295.                     if (sendto == -1)
  296.                         {
  297.                         top_output(OUT_SCREEN, getlang("NotLoggedIn"),
  298.                                    tmphand);
  299.                         return;
  300.                         }
  301.                     if (sendto == -2)
  302.                         {
  303.                         top_output(OUT_SCREEN, getlang("NotSpecific"),
  304.                                    tmphand);
  305.                         return;
  306.                         }
  307.                     if (sendto == -3)
  308.                         {
  309.                         top_output(OUT_SCREEN, getlang("HasForgotYou"),
  310.                                    handles[lastsendtonode].string);
  311.                         return;
  312.                         }
  313.                     if (sendto == -4)
  314.                         {
  315.                         top_output(OUT_SCREEN, getlang("NotInYourChannel"),
  316.                                    handles[lastsendtonode].string);
  317.                         return;
  318.                         }
  319.                     /* Check if action was done "secretly" (privately). */
  320.                     if (outbuf[1] != '\0' && cfg.allowprivmsgs &&
  321.                         user.security >= cfg.privmessagesec)
  322.                         {
  323.                         if (checkcmdmatch(&outbuf[1],
  324.                                           getlang("CmdsActionSecretly")) > 0)
  325.                             {
  326.                             msgtype = MSG_ACTPLUSEC;
  327.                             }
  328.                         }
  329.                     }
  330.                 strcpy(outbuf, useptr);
  331.                 }
  332.             break;
  333.         case ACT_TALKTYPE:
  334.             if (dowords == 1)
  335.                 {
  336.                 /* Handle the singular case. */
  337.                 useptr = actptrs[lnum][anum]->ptrs.singulartext;
  338.                 msgtype = MSG_TLKTYPSIN;
  339.                 doecho = user.pref1 & PREF1_ECHOTALKTYP;
  340.                 strcpy(outbuf, useptr);
  341.                 }
  342.             else
  343.                 {
  344.                 /* Handle any typed text. */
  345.                 useptr = actptrs[lnum][anum]->ptrs.pluraltext;
  346.                 msgtype = MSG_TLKTYPPLU;
  347.                 doecho = user.pref1 & PREF1_ECHOTALKTYP;
  348.                 outbuf = top_output(OUT_STRINGNF, getlang("TalkTypePrefix"),
  349.                                     useptr, "\0");
  350.                 msgextradata = strlen(outbuf);
  351.                 outbuf = top_output(OUT_STRINGNF, getlang("TalkTypePrefix"),
  352.                                     useptr, &word_str[word_pos[1]]);
  353.                 }
  354.             break;
  355.         }
  356.  
  357.     if (!useptr[0])
  358.         {
  359.         /* If there is no text in the output string, assume the sysop
  360.            specified "N/A" and issue an error. */
  361.         top_output(OUT_SCREEN, getlang("BadContext"),
  362.                    get_word(0),
  363.                    !actptrs[lnum][anum]->data.type ?
  364.                    getlang("Action") : getlang("TalkType"));
  365.         return;
  366.         }
  367.  
  368.     /* Display the response text, if any. */
  369.     if (actptrs[lnum][anum]->ptrs.responsetext[0] != '\0')
  370.         {
  371.         top_output(OUT_SCREEN, getlang("ActionResponse"),
  372.                    actptrs[lnum][anum]->ptrs.responsetext);
  373.         }
  374.  
  375.     /* Append "secretly" text if applicable. */
  376.     if (msgtype == MSG_ACTPLUSEC)
  377.         {
  378.         top_output(OUT_SCREEN, getlang("JustTo"), handles[sendto].string);
  379.         secret = 1;
  380.         }
  381.     top_output(OUT_SCREEN, getlang("ActionSuffix"));
  382.  
  383.     /* Display "message sent" notifications, if requested. */
  384.     if (msgtype == MSG_TLKTYPSIN && (user.pref1 & PREF1_TALKMSGSENT))
  385.         {
  386.         top_output(OUT_SCREEN, getlang("TalkTypeActionSent"));
  387.         }
  388.     if (msgtype == MSG_TLKTYPPLU && (user.pref1 & PREF1_TALKMSGSENT))
  389.         {
  390.         top_output(OUT_SCREEN, getlang("TalkTypeMsgSent"));
  391.         }
  392.  
  393.     if (lnum == 0)
  394.         {
  395.         char *ppp; /* strstr() result pointer. */
  396.  
  397.         /* Changes %P to nothing in personal actions, preventing users from
  398.            causing all sorts of problems.  This is a kludge fix; this should
  399.            really be detected when the actions are edited. */
  400.         Tempfix:
  401.         ppp = strstr(outbuf, "%p");
  402.         if (ppp == NULL)
  403.             {
  404.             ppp = strstr(outbuf, "%P");
  405.             }
  406.         if (ppp != NULL)
  407.             {
  408.             ppp[0] = '!';
  409.             goto Tempfix;
  410.             }
  411.         }
  412.  
  413.     dispatch_message(msgtype, outbuf, sendto, secret, doecho);
  414.  
  415.     }
  416.  
  417. /* action_list() - Display list(s) of actions to the user.
  418.    Parameters:  alwords - Number of words in the input string.
  419.    Returns:  Nothing.
  420.    Notes:  The string that is to be processed must first be parsed by the
  421.            split_string() function.
  422. */
  423. void action_list(XINT alwords)
  424.     {
  425.     /* Counter, list number to display, "all lists" flag/counter. */
  426.     XINT ald, alist = -1, alll;
  427.     char alines = 0, ans = 0; /* Line counter, nonstop flag. */
  428.  
  429.     if (alwords < 3)
  430.         {
  431.         /* If less than three words, assume user issued the list command by
  432.            itself and show the "list of lists" to the user. */
  433.         top_output(OUT_SCREEN, getlang("ActFileListPrefix"));
  434.         top_output(OUT_SCREEN, getlang("ActFileListHdr"));
  435.         top_output(OUT_SCREEN, getlang("ActFileListSep"));
  436.         for (ald = 0; ald <= numactfiles; ald++)
  437.             {
  438.             if (user.security >= actfiles[ald]->minsec &&
  439.                 user.security <= actfiles[ald]->maxsec &&
  440.                 curchannel >= actfiles[ald]->minchannel &&
  441.                 curchannel <= actfiles[ald]->maxchannel)
  442.                 {
  443.                 top_output(OUT_SCREEN, getlang("ActFileListItem"),
  444.                            cfg.actfilenames[ald], actfiles[ald]->name);
  445.                 }
  446.             }
  447.         top_output(OUT_SCREEN, getlang("ActFileListSuffix"));
  448.         }
  449.     else
  450.         {
  451.         /* Compare the third word of the input to each list name. */
  452.         for (ald = 0; ald <= numactfiles; ald++)
  453.             {
  454.             if (!stricmp(get_word(2), cfg.actfilenames[ald]) &&
  455.                 user.security >= actfiles[ald]->minsec &&
  456.                 user.security <= actfiles[ald]->maxsec &&
  457.                 curchannel >= actfiles[ald]->minchannel &&
  458.                 curchannel <= actfiles[ald]->maxchannel)
  459.                 {
  460.                 alll = alist = ald;
  461.                 break;
  462.                 }
  463.             }
  464.  
  465.         /* Test if all lists were requested. */
  466.         if (checkcmdmatch(get_word(2), getlang("CmdsActionListAll")))
  467.             {
  468.             alll = 0;
  469.             alist = numactfiles;
  470.             }
  471.  
  472.         /* Fail if no list number has been determined. */
  473.         if (alist < 0)
  474.             {
  475.             top_output(OUT_SCREEN, getlang("BadListName"));
  476.             return;
  477.             }
  478.  
  479.         /* Display the list to the user. */
  480.         top_output(OUT_SCREEN, getlang("ActListPrefix"));
  481.         /* This loop only executes once unless we're in "show all lists"
  482.            mode. */
  483.         for (; alll <= alist; alll++)
  484.             {
  485.             if (user.security >= actfiles[alll]->minsec &&
  486.                 user.security <= actfiles[alll]->maxsec &&
  487.                 curchannel >= actfiles[alll]->minchannel &&
  488.                 curchannel <= actfiles[alll]->maxchannel)
  489.                 {
  490.                 top_output(OUT_SCREEN, getlang("ActListHeader"),
  491.                            cfg.actfilenames[alll], actfiles[alll]->name);
  492.                 top_output(OUT_SCREEN, getlang("ActListLegend"));
  493.                 top_output(OUT_SCREEN, getlang("ActListSep"));
  494.                 for (ald = 0; ald < actfiles[alll]->numactions; ald++)
  495.                     {
  496.                     if (actptrs[alll][ald]->data.type == 0)
  497.                         {
  498.                         top_output(OUT_SCREEN,
  499.                                    getlang("ActListCharNormal"));
  500.                         }
  501.                     if (actptrs[alll][ald]->data.type == 1)
  502.                         {
  503.                         top_output(OUT_SCREEN,
  504.                                    getlang("ActListCharTType"));
  505.                         }
  506.                     top_output(OUT_SCREEN, getlang("ActListItem"),
  507.                                strlwr(actptrs[alll][ald]->data.verb));
  508.                     top_output(OUT_SCREEN, getlang("ActListItemSep"));
  509.                     /* Start a new line every six actions. */
  510.                     if ((ald + 1) % 6 == 0 ||
  511.                         ald == actfiles[alll]->numactions - 1)
  512.                         {
  513.                         top_output(OUT_SCREEN, getlang("ActListLineEnd"));
  514.                         alines++;
  515.                         /* Show a more prompt every 20 lines. */
  516.                         if (alines == 20 && !ans)
  517.                             {
  518.                             alines = 0;
  519.                             ans = moreprompt();
  520.                             if (ans == -1)
  521.                                 {
  522.                                 break;
  523.                                 }
  524.                             }
  525.                         }
  526.                     }
  527.                 /* If we're showing all the lists, reset for the next list. */
  528.                 if (alll < alist && !ans)
  529.                     {
  530.                     alines = 0;
  531.                     ans = moreprompt();
  532.                     if (ans == -1)
  533.                         {
  534.                         break;
  535.                         }
  536.                     }
  537.                 top_output(OUT_SCREEN, getlang("ActListSuffix"));
  538.                 }
  539.             }
  540.         }
  541.  
  542.     }
  543.  
  544. /* action_proc() - Process action-related commands.
  545.    Parameters:  awords - Number of words in input string.
  546.    Returns:  Nothing.
  547.    Notes:  The string that is to be processed must first be parsed by the
  548.            split_string() function.
  549. */
  550. void action_proc(XINT awords)
  551.     {
  552.  
  553.     /* List actions. */
  554.     if (checkcmdmatch(get_word(1), getlang("CmdsActionList")))
  555.         {
  556.         action_list(awords);
  557.         return;
  558.         }
  559.     /* Turn actions off. */
  560.     if (checkcmdmatch(get_word(1), getlang("CmdsActionOff")))
  561.         {
  562.         user.pref2 |= PREF2_ACTIONSOFF;
  563.         save_user_data(user_rec_num, &user);
  564.         top_output(OUT_SCREEN, getlang("ActionsNowOff"));
  565.         return;
  566.         }
  567.     /* Turn actions on. */
  568.     if (checkcmdmatch(get_word(1), getlang("CmdsActionOn")))
  569.         {
  570.         user.pref2 &= (0xFF - PREF2_ACTIONSOFF);
  571.         save_user_data(user_rec_num, &user);
  572.         top_output(OUT_SCREEN, getlang("ActionsNowOn"));
  573.         return;
  574.         }
  575.  
  576.     /* Command not recognized, show help file instead. */
  577.     show_helpfile("HELPACT0");
  578.  
  579.     }
  580.  
  581. /* loadpersactions() - Prepares the personal action list.
  582.    Parameters:  None.
  583.    Returns:  TRUE on success, FALSE on failure (usually out of memory).
  584. */
  585. char loadpersactions(void)
  586.     {
  587.     unsigned XINT lad; /* Counter. */
  588.     unsigned char *memchk = NULL; /* Errorcheck pointer. */
  589.  
  590.     /* This process is identical to the one used in the loadactions()
  591.        function.  The only difference is that the actions are copied from
  592.        the user's data instead of being loaded from a file. */
  593.     for (lad = 0; lad < 4; lad++)
  594.         {
  595.         actptrs[0][lad]->data.type = user.persact[lad].type;
  596.         strcpy(actptrs[0][lad]->data.verb, user.persact[lad].verb);
  597.         actptrs[0][lad]->data.responselen =
  598.             strlen(user.persact[lad].response);
  599.         actptrs[0][lad]->data.singularlen =
  600.             strlen(user.persact[lad].singular);
  601.         actptrs[0][lad]->data.plurallen =
  602.             strlen(user.persact[lad].plural);
  603.  
  604.         memchk = actptrs[0][lad]->ptrs.responsetext =
  605.             malloc(actptrs[0][lad]->data.responselen + 1);
  606.         if (memchk == NULL)
  607.             {
  608.             return 0;
  609.             }
  610.         memchk = actptrs[0][lad]->ptrs.singulartext =
  611.             malloc(actptrs[0][lad]->data.singularlen + 1);
  612.         if (memchk == NULL)
  613.             {
  614.             return 0;
  615.             }
  616.         memchk = actptrs[0][lad]->ptrs.pluraltext =
  617.             malloc(actptrs[0][lad]->data.plurallen + 1);
  618.         if (memchk == NULL)
  619.             {
  620.             return 0;
  621.             }
  622.         strcpy(actptrs[0][lad]->ptrs.responsetext,
  623.                user.persact[lad].response);
  624.         strcpy(actptrs[0][lad]->ptrs.singulartext,
  625.                user.persact[lad].singular);
  626.         strcpy(actptrs[0][lad]->ptrs.pluraltext,
  627.                user.persact[lad].plural);
  628.         }
  629.  
  630.     return 1;
  631.     }
  632.  
  633.