Crossfire Server, Branch 1.12  R12190
dialog.c
Go to the documentation of this file.
00001 /*
00002     CrossFire, A Multiplayer game for X-windows
00003 
00004     Copyright (C) 2008 Crossfire Development Team
00005     Copyright (C) 1992 Frank Tore Johansen
00006 
00007     This program is free software; you can redistribute it and/or modify
00008     it under the terms of the GNU General Public License as published by
00009     the Free Software Foundation; either version 2 of the License, or
00010     (at your option) any later version.
00011 
00012     This program is distributed in the hope that it will be useful,
00013     but WITHOUT ANY WARRANTY; without even the implied warranty of
00014     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015     GNU General Public License for more details.
00016 
00017     You should have received a copy of the GNU General Public License
00018     along with this program; if not, write to the Free Software
00019     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 
00021     The authors can be reached via e-mail at crossfire-devel@real-time.com
00022 */
00023 
00029 #include <string.h>
00030 #include "global.h"
00031 #include "define.h"
00032 #include "object.h"
00033 #include "dialog.h"
00034 
00039 void free_dialog_information(object *op) {
00040     struct_dialog_message *current, *next;
00041     struct_dialog_reply *currep, *nextrep;
00042 
00043     if (!QUERY_FLAG(op, FLAG_DIALOG_PARSED))
00044         return;
00045 
00046     CLEAR_FLAG(op, FLAG_DIALOG_PARSED);
00047     if (!op->dialog_information)
00048         return;
00049 
00050     current = op->dialog_information->all_messages;
00051     while (current) {
00052         next = current->next;
00053         free(current->match);
00054         free(current->message);
00055         currep = current->replies;
00056         while (currep) {
00057             nextrep = currep->next;
00058             free(currep->reply);
00059             free(currep->message);
00060             currep = nextrep;
00061         }
00062         free(current);
00063         current = next;
00064     }
00065 
00066     currep = op->dialog_information->all_replies;
00067     while (currep) {
00068         nextrep = currep->next;
00069         free(currep->reply);
00070         free(currep->message);
00071         free(currep);
00072         currep = nextrep;
00073     }
00074 
00075     free(op->dialog_information);
00076     op->dialog_information = NULL;
00077 }
00078 
00086 static int matches(const char *exp, const char *text) {
00087     char *pipe, *save, *msg;
00088     int match = 0;
00089 
00090     if (exp[0] == '*')
00091         return 1;
00092 
00093     msg = strdup(exp);
00094 
00095     pipe = strtok_r(msg, "|", &save);
00096     while (pipe) {
00097         if (re_cmp(text, pipe)) {
00098             match = 1;
00099             break;
00100         }
00101         pipe = strtok_r(NULL, "|", &save);
00102     }
00103 
00104     free(msg);
00105     return match;
00106 }
00107 
00114 static void parse_dialog_information(object *op) {
00115     struct_dialog_message *message = NULL, *last = NULL;
00116     struct_dialog_reply *reply = NULL;
00117     char *current, *save, *msg, *cp;
00118     int len;
00119     /* Used for constructing message with */
00120     char *tmp = NULL;
00121     size_t tmplen = 0;
00122 
00123     if (QUERY_FLAG(op, FLAG_DIALOG_PARSED))
00124         return;
00125     SET_FLAG(op, FLAG_DIALOG_PARSED);
00126 
00127     op->dialog_information = (struct_dialog_information *)calloc(1, sizeof(struct_dialog_information));
00128 
00129     if (!op->msg)
00130         return;
00131 
00132     msg = strdup(op->msg);
00133     current = strtok_r(msg, "\n", &save);
00134 
00135     while (current) {
00136         if (strncmp(current, "@match ", 7) == 0) {
00137             if (message) {
00138                 message->message = tmp;
00139                 tmp = NULL;
00140                 tmplen = 0;
00141             }
00142 
00143             message = (struct_dialog_message *)calloc(1, sizeof(struct_dialog_message));
00144             if (last)
00145                 last->next = message;
00146             else
00147                 op->dialog_information->all_messages = message;
00148             last = message;
00149 
00150             message->match = strdup(current+7);
00151         } else if ((strncmp(current, "@reply ", 7) == 0 && (len = 7)) || (strncmp(current, "@question ", 10) == 0 && (len = 10))) {
00152             if (message) {
00153                 reply = (struct_dialog_reply *)calloc(1, sizeof(struct_dialog_reply));
00154                 reply->type = (len == 7 ? rt_reply : rt_question);
00155                 cp = strchr(current+len, ' ');
00156                 if (cp) {
00157                     *cp = '\0';
00158                     reply->reply = strdup(current+len);
00159                     reply->message = strdup(cp+1);
00160                 } else {
00161                     reply->reply = strdup(current+len);
00162                     reply->message = strdup(reply->reply);
00163                     LOG(llevDebug, "Warning: @reply/@question without message for %s!\n", op->name);
00164                 }
00165                 reply->next = message->replies;
00166                 message->replies = reply;
00167 
00168                 reply = (struct_dialog_reply *)calloc(1, sizeof(struct_dialog_reply));
00169                 reply->reply = strdup(message->replies->reply);
00170                 reply->message = strdup(message->replies->message);
00171                 reply->type = message->replies->type;
00172                 reply->next = op->dialog_information->all_replies;
00173                 op->dialog_information->all_replies = reply;
00174             } else
00175                 LOG(llevDebug, "Warning: @reply not in @match block for %s!\n", op->name);
00176         } else if (message) {
00177             /* Needed to set initial \0 */
00178             int wasnull = FALSE;
00179             tmplen += strlen(current)+2;
00180             if (!tmp)
00181                 wasnull = TRUE;
00182             tmp = realloc(tmp, tmplen*sizeof(char));
00183             if (!tmp)
00184                 fatal(OUT_OF_MEMORY);
00185             if (wasnull)
00186                 tmp[0] = 0;
00187             strncat(tmp, current, tmplen-strlen(tmp)-1);
00188             strncat(tmp, "\n", tmplen-strlen(tmp)-1);
00189         }
00190         current = strtok_r(NULL, "\n", &save);
00191     }
00192 
00193     if (message) {
00194         if (!tmp)
00195             message->message = strdup("");
00196         else
00197             message->message = tmp;
00198         tmp = NULL;
00199         tmplen = 0;
00200     }
00201 
00202     free(msg);
00203 }
00204 
00214 int get_dialog_message(object *op, const char *text, struct_dialog_message **message, struct_dialog_reply **reply) {
00215     if (!QUERY_FLAG(op, FLAG_DIALOG_PARSED))
00216         parse_dialog_information(op);
00217 
00218     for (*message = op->dialog_information->all_messages; *message; *message = (*message)->next) {
00219         if (matches((*message)->match, text)) {
00220             break;
00221         }
00222     }
00223     if (!*message)
00224         return 0;
00225 
00226     for (*reply = op->dialog_information->all_replies; *reply; *reply = (*reply)->next) {
00227         if (strcmp((*reply)->reply, text) == 0)
00228             break;
00229     }
00230 
00231     return 1;
00232 }