PageRenderTime 56ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 1ms

/mod/alice.cpp

https://gitlab.com/b0nk/mbot
C++ | 1650 lines | 1390 code | 101 blank | 159 comment | 474 complexity | 9489f12fe2e13249a3019cada2dc4e00 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. This file is part of mbot.
  3. mbot is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or (at
  6. your option) any later version.
  7. mbot is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with mbot; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #include "mbot.h"
  16. #define SOURCE s->script.source
  17. #define DEST s->script.dest
  18. #define SEND_TEXT s->script.send_text
  19. #define MAX_VARNAME_SIZE 40 // max size the name of a var can be
  20. #define MAX_VARVAL_SIZE MSG_SIZE // max size the value of a var can be
  21. #define MAX_LINE_SIZE 16384 // max size a line of text can be
  22. #define MAX_RANDLIST_SIZE 200 // max # of <li></li> in a random
  23. #define MAX_SRAI 20 // max <srai> followed in a response
  24. /////////////////////
  25. // class definition
  26. /////////////////////
  27. class ModAlice {
  28. public:
  29. ModAlice (NetServer *, c_char, c_char, Log *);
  30. ~ModAlice (void);
  31. // Breaks lines, cleans up text and logs, then sends to respond2
  32. char *respond (char *);
  33. int setvar (bool, c_char, c_char);
  34. // saves internal variables to file
  35. void savevars (c_char);
  36. // saves default vars to a new file. Also loads defaults into memory
  37. void loadvars (c_char);
  38. NetServer *s;
  39. bool initialized;
  40. private:
  41. c_char getvar (c_char varname, c_char vardefault);
  42. // checks a line of AIML for syntax errors
  43. int checkline (char *line);
  44. // splits the aiml files into patterns.txt and templates.txt
  45. int prepare (c_char);
  46. // makes alice's answer pretty. (cleans up text)
  47. void print (char *line);
  48. // makes substitutions on text
  49. void substitute (Text &subst, char *text);
  50. // gets a response
  51. char *respond2 (char *text);
  52. void replacer (char *line);
  53. int splitaiml (c_char, fstream &);
  54. int match (c_char text, c_char pattern, int final);
  55. void randomize (char *text);
  56. void reevaluate (char *line );
  57. struct var_array {
  58. bool protect;
  59. int def;
  60. String varname;
  61. String value;
  62. var_array *next;
  63. var_array (bool p, int d, c_char vn, c_char v, var_array *n) : protect (p),
  64. def (d), varname (vn, MAX_VARNAME_SIZE), value (v, MAX_VARVAL_SIZE),
  65. next (n) {}
  66. };
  67. /* star holds "*" and "_", that holds our that, pbuffer is sort of
  68. a general scrap variable, although it does eventually hold our answer. */
  69. char star[MAX_LINE_SIZE+1], that[MAX_LINE_SIZE+1];
  70. char pbuffer[MAX_LINE_SIZE+1];
  71. // best holds the pattern matched
  72. String best;
  73. // char's for our init file
  74. fstream templatefile, patternfile;
  75. Text personfile, person2file, substitutefile, personffile;
  76. String datafile;
  77. // should we log?
  78. bool logging, log_error;
  79. Log *log;
  80. // new variables for the getvar setvar code
  81. var_array *root_var;
  82. // file positions for each letter
  83. long chunk[28];
  84. // these 4 are for checkline()
  85. int cc; // checkcount
  86. bool hp, // have we had a pattern?
  87. hh, // had that?
  88. he; // had template?
  89. /* topic holds our topic which we convert to conditional tags. */
  90. /* this isn't coded yet */
  91. char topic[MAX_VARVAL_SIZE+1];
  92. String vars;
  93. int srai_num; // number of <srai> tags followed in a response
  94. };
  95. List *alice_list;
  96. ///////////////
  97. // prototypes
  98. ///////////////
  99. // removes all spaces including '\t' '\v' ...
  100. static void spacetrim (char *line);
  101. // finds string from end
  102. static char *strlstr (char *line, c_char token);
  103. static void stripurl (char *line );
  104. // replaces string1 with string2 in line
  105. static int replace (char *line, c_char string1, c_char string2);
  106. // removes all the text from first to last
  107. static void strremove (char *text, c_char first, c_char last);
  108. // cleans up text
  109. static void cleaner (char *text);
  110. static ModAlice *server2alice (NetServer *);
  111. static void alice_event (NetServer *);
  112. static void alice_conf (NetServer *, c_char);
  113. static void alice_stop (void);
  114. static void alice_start (void);
  115. extern "C" {
  116. EXPORT struct Module::module_type module = {
  117. MODULE_VERSION,
  118. "alice",
  119. alice_start,
  120. alice_stop,
  121. alice_conf,
  122. NULL
  123. };
  124. }
  125. //////////////////
  126. // alice helpers
  127. //////////////////
  128. // delete spaces from the beginning and end of <line>
  129. void
  130. spacetrim (char *line)
  131. {
  132. int i = 0;
  133. while (isspace (line[i]))
  134. i++;
  135. if (i != 0)
  136. strcpy (line, line+i);
  137. while ((i = strlen (line)-1) >= 0)
  138. if (isspace (line[i]))
  139. line[i] = 0;
  140. else
  141. break;
  142. }
  143. char *
  144. strlstr (char *line, c_char token)
  145. {
  146. char *pos = NULL;
  147. while ((line = strstr (line, token)))
  148. {
  149. pos = line;
  150. line++;
  151. }
  152. return pos;
  153. }
  154. void
  155. stripurl (char *line)
  156. {
  157. strremove (line, "<a href=", ">");
  158. replace (line, "</a>", "");
  159. strremove (line, "<A HREF=", ">");
  160. replace (line, "</A>", "");
  161. while (replace (line, "<br>", ""));
  162. while (replace (line, "<BR>", ""));
  163. replace (line, "<ul>", "");
  164. while (replace (line, "<li>", ""));
  165. while (replace (line, "</li>", ""));
  166. replace (line, "</ul>", "");
  167. strremove (line, "<APPLET", "</APPLET>");
  168. strremove (line, "<applet", "</applet>");
  169. replace (line, "&lt;", "<");
  170. replace (line, "&gt;", ">");
  171. replace (line, "\n", "");
  172. }
  173. void
  174. strremove (char *text, c_char first, c_char last)
  175. {
  176. char *pos1, *pos2;
  177. if (!first || !last || !text)
  178. return;
  179. if (!(pos1 = strstr (text, first)))
  180. return;
  181. if (!(pos2 = strstr (pos1, last)))
  182. return;
  183. if (pos1 >= pos2)
  184. return;
  185. pos2 += strlen (last);
  186. memmove (pos1, pos2, strlen (pos2) + 1);
  187. }
  188. int
  189. replace (char *string, c_char strfrom, c_char strto)
  190. {
  191. char *pos, *tmp;
  192. size_t len, len2;
  193. if (!string || !strfrom || !strto)
  194. return 0;
  195. pos = strstr (string, strfrom);
  196. if (!pos)
  197. return 0;
  198. len = strlen (strfrom);
  199. len2 = strlen (strto);
  200. if (len > len2)
  201. {
  202. tmp = pos + len - len2;
  203. memmove (pos, tmp, strlen (tmp) + 1);
  204. }
  205. if (len < len2)
  206. {
  207. char buf[MAX_LINE_SIZE+1];
  208. int buflen;
  209. tmp = pos + len;
  210. buflen = strlen (tmp) + 1;
  211. memcpy (buf, tmp, buflen);
  212. memcpy (pos + len2, buf, buflen);
  213. }
  214. strncpy (pos, strto, len2);
  215. return 1;
  216. }
  217. void
  218. cleaner (char *text)
  219. {
  220. char symb;
  221. char *oldtext = text;
  222. while ((symb = *text))
  223. if (isalnum (symb) || symb == ' ' || symb == '-')
  224. text++;
  225. else
  226. memmove (text, text + 1, strlen (text) + 1);
  227. spacetrim (oldtext);
  228. }
  229. ////////////////////
  230. // class functions
  231. ////////////////////
  232. ModAlice::ModAlice (NetServer *server, c_char init_file, c_char v, Log *l) :
  233. s (server), initialized (0), best (PATH_MAX), datafile (PATH_MAX),
  234. log (l), root_var (NULL), cc (0), hp (0), hh (0), he (0), vars (v, PATH_MAX)
  235. {
  236. StringFixed aimlscrap (PATH_MAX), patternscrap (PATH_MAX),
  237. templatescrap (PATH_MAX);
  238. // load up the init file
  239. ifstream init (init_file);
  240. if (!init)
  241. {
  242. s->write_botlog ("can't open init file %s: %s", init_file, strerror (errno));
  243. return;
  244. }
  245. // we use pbuffer as a scrap variable
  246. char *comment, *epos;
  247. while (init.getline (pbuffer, MAX_LINE_SIZE))
  248. {
  249. // eliminate comments
  250. comment = strchr (pbuffer, '#');
  251. if (comment != NULL)
  252. comment[0] = 0;
  253. // delete all spaces
  254. while (replace (pbuffer, " ", ""));
  255. strip_crlf (pbuffer);
  256. epos = strchr (pbuffer, '=');
  257. epos++;
  258. if (strstr (pbuffer, "aimlfile"))
  259. aimlscrap = epos;
  260. else if (strstr (pbuffer, "datafile"))
  261. datafile = epos;
  262. else if (strstr (pbuffer, "personfile")
  263. && !personfile.read_file (epos))
  264. {
  265. s->write_botlog ("error opening personfile %s: %s", epos, strerror (errno));
  266. return;
  267. }
  268. else if (strstr (pbuffer, "person2file")
  269. && !person2file.read_file (epos))
  270. {
  271. s->write_botlog ("error opening person2file %s: %s", epos, strerror (errno));
  272. return;
  273. }
  274. else if (strstr (pbuffer, "personffile")
  275. && !personffile.read_file (epos))
  276. {
  277. s->write_botlog ("error opening personffile %s: %s", epos, strerror (errno));
  278. return;
  279. }
  280. else if (strstr (pbuffer, "substitutefile")
  281. && !substitutefile.read_file (epos))
  282. {
  283. s->write_botlog ("error opening substitutefile %s: %s", epos, strerror (errno));
  284. return;
  285. }
  286. else if (strstr (pbuffer, "patternfile"))
  287. patternscrap = epos;
  288. else if (strstr (pbuffer, "templatefile"))
  289. templatescrap = epos;
  290. else if (strstr (pbuffer, "logging"))
  291. {
  292. if (*epos == 'y' || *epos == 'Y' || *epos == '1')
  293. logging = 1;
  294. else
  295. logging = 0;
  296. }
  297. else if (strstr (pbuffer, "log_error"))
  298. {
  299. if (*epos == 'y' || *epos == 'Y' || *epos == '1')
  300. log_error = 1;
  301. else
  302. log_error = 0;
  303. }
  304. }
  305. // check to see if it needs to create new patterns.txt and templates.txt
  306. #ifdef HAS_IOS_BINARY
  307. patternfile.open (patternscrap, ios::in | ios::out | IOS_NOCREATE | ios::binary);
  308. templatefile.open (templatescrap, ios::in | ios::out | IOS_NOCREATE | ios::binary);
  309. #else
  310. patternfile.open (patternscrap, ios::in | ios::out | IOS_NOCREATE);
  311. templatefile.open (templatescrap, ios::in | ios::out | IOS_NOCREATE);
  312. #endif
  313. if (!patternfile || !templatefile)
  314. {
  315. if (!(!patternfile))
  316. patternfile.close ();
  317. if (!(!templatefile))
  318. templatefile.close ();
  319. patternfile.clear ();
  320. #ifdef HAS_IOS_BINARY
  321. patternfile.open (patternscrap, ios::in | ios::out | ios::trunc | ios::binary);
  322. #else
  323. patternfile.open (patternscrap, ios::in | ios::out | ios::trunc);
  324. #endif
  325. if (!patternfile)
  326. {
  327. s->write_botlog ("error creating patternfile %s: %s", (c_char)patternscrap, strerror (errno));
  328. return;
  329. }
  330. templatefile.clear ();
  331. #ifdef HAS_IOS_BINARY
  332. templatefile.open (templatescrap, ios::in | ios::out | ios::trunc | ios::binary);
  333. #else
  334. templatefile.open (templatescrap, ios::in | ios::out | ios::trunc);
  335. #endif
  336. if (!templatefile)
  337. {
  338. s->write_botlog ("error creating templatefile %s: %s", (c_char)templatescrap, strerror (errno));
  339. return;
  340. }
  341. if (!prepare (aimlscrap))
  342. return;
  343. patternfile.clear ();
  344. patternfile.seekg (0);
  345. templatefile.clear ();
  346. templatefile.seekg(0);
  347. }
  348. else
  349. {
  350. // ok, this part really should be saved to a file upon preparation
  351. char last = 0;
  352. while (1)
  353. {
  354. long line;
  355. line = patternfile.tellg ();
  356. if (!patternfile.getline (pbuffer, MAX_LINE_SIZE))
  357. break;
  358. char first = pbuffer[0];
  359. if ((first < 'A') || (first > 'Z'))
  360. first = 'Z' + 1;
  361. if (first != last)
  362. {
  363. last = first;
  364. if ((last < 'A') || (last > 'Z'))
  365. last = 'Z' + 1;
  366. chunk[last - 'A'] = line;
  367. }
  368. }
  369. }
  370. loadvars (vars);
  371. initialized = 1;
  372. }
  373. ModAlice::~ModAlice (void)
  374. {
  375. savevars (vars);
  376. var_array *varsnext;
  377. while (root_var != NULL)
  378. {
  379. varsnext = root_var->next;
  380. delete root_var;
  381. root_var = varsnext;
  382. }
  383. }
  384. int
  385. ModAlice::setvar (bool protect, c_char var, c_char value)
  386. {
  387. String varname (var, MAX_VARNAME_SIZE);
  388. varname.lower ();
  389. if (root_var == NULL) // the variable list is empty, create the first
  390. {
  391. if (value[0] == '*')
  392. root_var = new var_array (protect, 1, varname, value+1, NULL);
  393. else
  394. root_var = new var_array (protect, 0, varname, value, NULL);
  395. if (root_var == NULL)
  396. return 0;
  397. if (root_var->def == 0)
  398. return 1;
  399. return 2;
  400. }
  401. // we search through the list for the name
  402. var_array *conductor = root_var;
  403. while (conductor != NULL)
  404. {
  405. if (conductor->varname == varname)
  406. {
  407. if (protect == 1 || conductor->protect == protect)
  408. conductor->value = value;
  409. else
  410. return 0;
  411. if (conductor->def == 0)
  412. return 1;
  413. return 2;
  414. }
  415. conductor = conductor->next;
  416. }
  417. // if we get here, the variable doesn't exist, create a new entry
  418. if (value[0] == '*')
  419. conductor = new var_array (protect, 1, varname, value+1, root_var);
  420. else
  421. conductor = new var_array (protect, 0, varname, value, root_var);
  422. if (conductor == NULL)
  423. return 0;
  424. root_var = conductor;
  425. if (conductor->def == 0)
  426. return 1;
  427. return 2;
  428. }
  429. /*
  430. return <var>'s text. if <var> doesn't exist, return <vardefault>, and if
  431. it's not NULL, also create <var> with it
  432. */
  433. c_char
  434. ModAlice::getvar (c_char var, c_char vardefault)
  435. {
  436. if (strlen (var) > MAX_VARNAME_SIZE)
  437. return NULL;
  438. String varname (var, MAX_VARNAME_SIZE);
  439. varname.lower ();
  440. // we begin searching through the linked list
  441. var_array *conductor = root_var;
  442. while (conductor != NULL)
  443. {
  444. if (conductor->varname == varname)
  445. return conductor->value;
  446. conductor = conductor->next;
  447. }
  448. // if we made it to here, the variable doesn't exist
  449. if (vardefault == NULL)
  450. return NULL;
  451. // create a new with the default value
  452. setvar (0, varname, vardefault);
  453. return vardefault;
  454. }
  455. char *
  456. ModAlice::respond (char *text)
  457. {
  458. /* Thanks to Dr. Wallace for writing this into the CGI,
  459. it was stripped out of there, modified slightly,
  460. then added to here. */
  461. char scrap[MAX_LINE_SIZE+1];
  462. char *ltimestr, *uip, *strtmp;
  463. struct tm *ltime;
  464. time_t clock;
  465. time (&clock);
  466. ltime = localtime (&clock);
  467. ltimestr = asctime (ltime);
  468. srai_num = 0;
  469. my_strncpy (scrap, text, MAX_LINE_SIZE);
  470. substitute (substitutefile, scrap);
  471. /* perhaps some code to deal with remaining periods that are not
  472. sentence breaks. (Like 5.02 or H.I.P.P.i.e.) */
  473. while (replace (scrap, "?", "."));
  474. while (replace (scrap, "!", "."));
  475. while (replace (scrap, "\n", ""));
  476. // we need to make sure our sentence ends in a period
  477. if (scrap[strlen (scrap)-2] != '.')
  478. strncat (scrap, ".", MAX_LINE_SIZE-strlen (scrap));
  479. uip = scrap;
  480. char oneline[MAX_LINE_SIZE+1];
  481. char output[MAX_LINE_SIZE+1];
  482. output[0] = 0;
  483. do
  484. {
  485. memset (oneline, 0, MAX_LINE_SIZE);
  486. // skip white space:
  487. while (uip[0] == ' ')
  488. uip++;
  489. my_strncpy (oneline, uip, MAX_LINE_SIZE);
  490. if (strstr (uip, ".") > 0)
  491. {
  492. // advance to next sentence:
  493. uip = strstr (uip, ".")+1;
  494. // strip out first sentence:
  495. strtmp = strstr (oneline, ".");
  496. if (strtmp != NULL)
  497. strtmp[0] = 0;
  498. }
  499. if (oneline != NULL && strlen (oneline) > 0)
  500. {
  501. // Robot Respose:
  502. cleaner (oneline);
  503. strncat (output, respond2 (oneline), MAX_LINE_SIZE-strlen (output));
  504. if (logging && log != NULL)
  505. {
  506. *log << CMD[0] << ": " << oneline << EOL;
  507. *log << s->nick << ": " << output << EOL;
  508. }
  509. strncat (output, " ", MAX_LINE_SIZE-strlen (output));
  510. }
  511. }
  512. while (strstr (uip, ".") > 0); // any more sentences?
  513. strcpy (pbuffer, output);
  514. print (pbuffer);
  515. return pbuffer;
  516. }
  517. void
  518. ModAlice::savevars (c_char varfile)
  519. {
  520. ofstream f (varfile, ios::out | ios::trunc);
  521. // first we print out that
  522. f << that << '\n';
  523. // we print out each variable
  524. var_array *conductor = root_var;
  525. while (conductor != NULL)
  526. {
  527. if (conductor->def == 1)
  528. f << conductor->protect << ' ' << conductor->varname << "=*" << conductor->value << '\n';
  529. else
  530. f << conductor->protect << ' ' << conductor->varname << '=' << conductor->value << '\n';
  531. conductor = conductor->next;
  532. }
  533. }
  534. void
  535. ModAlice::loadvars (c_char varfile)
  536. {
  537. // first wipe out our existing variables
  538. var_array *conductor = root_var;
  539. while (conductor != NULL)
  540. {
  541. conductor = conductor->next;
  542. delete root_var;
  543. root_var = conductor;
  544. }
  545. // next we see if varfile exists
  546. char scrap[MAX_LINE_SIZE+1], scrap2[MAX_LINE_SIZE+1];
  547. #ifdef HAS_IOS_BINARY
  548. ifstream f (varfile, ios::in | ios::binary | IOS_NOCREATE);
  549. #else
  550. ifstream f (varfile, ios::in | IOS_NOCREATE);
  551. #endif
  552. if (!f)
  553. {
  554. // if not, we load up defvars.txt into our varfile, and into memory
  555. loadvars (datafile);
  556. savevars (varfile);
  557. }
  558. else
  559. {
  560. // if so, we load up variables from it into memory
  561. // first we grab that
  562. f.getline (that, MAX_LINE_SIZE);
  563. // now we load up our vars
  564. while (f.getline (scrap, MAX_LINE_SIZE))
  565. {
  566. if (!(strstr (scrap, "=")))
  567. continue;
  568. my_strncpy (scrap2, scrap + 2, MAX_LINE_SIZE);
  569. scrap[1] = 0;
  570. int protect = atoi (scrap);
  571. my_strncpy (scrap, scrap2, MAX_LINE_SIZE);
  572. *strchr (scrap, '=') = 0;
  573. char *varname = scrap;
  574. char *value = strstr (scrap2, "=")+1;
  575. setvar (protect, varname, value);
  576. }
  577. }
  578. }
  579. void
  580. ModAlice::replacer (char *line)
  581. {
  582. char *pos;
  583. replace (line, "<alice>", "");
  584. replace (line, "<category>", "");
  585. replace (line, "</category>", "");
  586. replace (line, "</alice>", "");
  587. if ((pos = strstr (line, "<topic name=\"")))
  588. {
  589. my_strncpy (topic, pos, MAX_VARVAL_SIZE);
  590. *strstr (topic, "\"") = 0;
  591. }
  592. if (strstr (line, "</topic>"))
  593. topic[0] = 0;
  594. strremove (line, "<topic", ">");
  595. replace (line, "</topic>", "");
  596. while (replace (line, "<getversion/>", "<getvar name=\"version\"/>"));
  597. while (replace (line, "<set_animagent/>", "<setvar name=\"animagent\">on</setvar>"));
  598. while (replace (line, "<person/>", "<person><star/></person>"));
  599. while (replace (line, "<person2/>", "<person2><star/></person2>"));
  600. while (replace (line, "<personf/>", "<personf><star/></personf>"));
  601. while (replace (line, "<setname/>", "<setvar name=\"name\"/><star/></setvar>"));
  602. while (replace (line, "<birthday/>", "<getvar name=\"botbirthday\"/>"));
  603. while (replace (line, "<birthplace/>", "<getvar name=\"botbirthplace\"/>"));
  604. while (replace (line, "<botasmter/>", "<getvar name=\"botasmter\"/>"));
  605. while (replace (line, "<botmaster/>", "<getvar name=\"botmaster\"/>"));
  606. while (replace (line, "<boyfriend/>", "<getvar name=\"botboyfriend\"/>"));
  607. while (replace (line, "<favorite_band/>", "<getvar name=\"botband\"/>"));
  608. while (replace (line, "<favorite_book/>", "<getvar name=\"botbook\"/>"));
  609. while (replace (line, "<favorite_color/>", "<getvar name=\"botcolor\"/>"));
  610. while (replace (line, "<favorite_food/>", "<getvar name=\"botfood\"/>"));
  611. while (replace (line, "<favorite_movie/>", "<getvar name=\"botmovie\"/>"));
  612. while (replace (line, "<favorite_song/>", "<getvar name=\"botsong\"/>"));
  613. while (replace (line, "<for_fun/>", "<getvar name=\"botfun\"/>"));
  614. while (replace (line, "<friends/>", "<getvar name=\"botfriends\"/>"));
  615. while (replace (line, "<gender/>", "<getvar name=\"botgender\"/>"));
  616. while (replace (line, "<getname/>", "<getvar name=\"name\"/>"));
  617. while (replace (line, "<get_does/>", "<getvar name=\"does\"/>"));
  618. while (replace (line, "<get_gender/>", "<getvar name=\"gender\"/>"));
  619. while (replace (line, "<getsize/>", "<getvar name=\"botsize\"/>"));
  620. while (replace (line, "<gettopic/>", "<getvar name=\"topic\"/>"));
  621. while (replace (line, "<girlfriend/>", "<getvar name=\"botgirlfriend\"/>"));
  622. while (replace (line, "<location/>", "<getvar name=\"botlocation\"/>"));
  623. while (replace (line, "<look_like/>", "<getvar name=\"botlooks\"/>"));
  624. while (replace (line, "<name/>", "<getvar name=\"botname\"/>"));
  625. while (replace (line, "<kind_music/>", "<getvar name=\"botmusic\"/>"));
  626. while (replace (line, "<question/>", "<getvar name=\"question\"/>"));
  627. while (replace (line, "<sign/>", "<getvar name=\"botsign\"/>"));
  628. while (replace (line, "<talk_about/>", "<getvar name=\"bottalk\"/>"));
  629. while (replace (line, "<they/>", "<getvar name=\"they\"/>"));
  630. while (replace (line, "<wear/>", "<getvar name=\"botwear\"/>"));
  631. while (replace (line, "<setname>", "<setvar name=\"name\">"));
  632. while (replace (line, "</setname>", "</setvar>"));
  633. while (replace (line, "<settopic>", "<setvar name=\"topic\">"));
  634. while (replace (line, "</settopic>", "</setvar>"));
  635. while (replace (line, "<set_does>", "<setvar name=\"does\">"));
  636. while (replace (line, "<set_it>", "<setvar name=\"it\">"));
  637. while (replace (line, "</set_it>", "</setvar>"));
  638. while (replace (line, "<set_personality>", "<setvar name=\"personality\">"));
  639. while (replace (line, "</set_personality>", "</setvar>"));
  640. while (replace (line, "<set_female/>","<setvar name=\"gender\">she</setvar>"));
  641. while (replace (line, "<set_male/>","<setvar name=\"gender\">he</setvar>"));
  642. // need code to handle get_??? and set_???
  643. while ((pos = strstr(line, "<get_")))
  644. {
  645. replace (pos, "<get_", "<getvar name=\"");
  646. replace (pos, "/>", "\"/>");
  647. }
  648. while ((pos = strstr (line, "<set_")))
  649. {
  650. replace (pos, "<set_", "<setvar name=\"");
  651. replace (pos, ">", "\">");
  652. if (replace (pos, "</se", "</setvar>"))
  653. {
  654. pos = strstr (pos, "</setvar>") + 9;
  655. strremove (pos, "t_", ">");
  656. }
  657. }
  658. while (replace (line, "<sr/>", "<srai><star/></srai>"));
  659. while (replace (line, "\n", ""));
  660. }
  661. int
  662. ModAlice::checkline (char *line)
  663. {
  664. /* this performs syntax checking on the AIML.
  665. ok, what we've got is a global int called cc. If we have a
  666. tag we add the appropiate value. If we have a /tag we subtract that
  667. value.
  668. The values go as follows.
  669. <alice> = ba = +1 </alice> = ea = -1
  670. <topic> = bt = 2
  671. category = bc = 4
  672. pattern = bp = 8
  673. that = bh = 16
  674. template = be = 32
  675. */
  676. int ba = 0, ea = 0; // <alice> begin and end
  677. int bt = 0, et = 0; // <topic>
  678. int bc = 0, ec = 0; // <category>
  679. int bp = 0, ep = 0; // <pattern>
  680. int bh = 0, eh = 0; // <that>
  681. int be = 0, ee = 0; // <template>
  682. if (strstr (line, "<alice>"))
  683. ba = 1;
  684. if (strstr (line, "</alice>"))
  685. ea = 1;
  686. if (strstr (line, "<topic"))
  687. bt = 1;
  688. if (strstr (line, "</topic>"))
  689. et = 1;
  690. if (strstr (line, "<category>"))
  691. bc = 1;
  692. if (strstr (line, "</category>"))
  693. ec = 1;
  694. if (strstr (line, "<pattern>"))
  695. bp = 1;
  696. if (strstr (line, "</pattern>"))
  697. ep = 1;
  698. if (strstr (line, "<that>"))
  699. bh = 1;
  700. if (strstr (line, "</that>"))
  701. eh = 1;
  702. if (strstr (line, "<template>"))
  703. be = 1;
  704. if (strstr (line, "</template>"))
  705. ee = 1;
  706. if (ba)
  707. {
  708. if (cc != 0)
  709. return 0;
  710. cc += 1;
  711. }
  712. if (bt)
  713. {
  714. if (cc != 1)
  715. return 0;
  716. cc += 2;
  717. }
  718. if (bc)
  719. {
  720. if (cc !=1 && cc != 3)
  721. return 0;
  722. cc += 4;
  723. }
  724. if (bp)
  725. {
  726. if (!(cc & 1) || !(cc & 4))
  727. return 0;
  728. cc += 8;
  729. }
  730. if (ep)
  731. {
  732. if (!(cc & 1) || !(cc & 4) || hh || he || !(cc & 8))
  733. return 0;
  734. cc -= 8;
  735. hp = 1;
  736. }
  737. if (bh)
  738. {
  739. if (!(cc & 1) || !(cc & 4) || !(hp) || he)
  740. return 0;
  741. cc += 16;
  742. }
  743. if (eh)
  744. {
  745. if (!(cc & 1) || !(cc & 4) || !(hp) || he || !(cc & 16))
  746. return 0;
  747. cc -= 16;
  748. hh = 1;
  749. }
  750. if (be)
  751. {
  752. if (!(cc & 1) || !(cc & 4) || !hp)
  753. return 0;
  754. cc += 32;
  755. }
  756. if (ee)
  757. {
  758. if (!(cc & 1) || !(cc & 4) || !(hp) || !(cc & 32))
  759. return 0;
  760. cc -= 32;
  761. he = 1;
  762. }
  763. if (ec)
  764. {
  765. if (!(cc & 1) || !(cc & 4) || !hp || !he)
  766. return 0;
  767. cc -= 4;
  768. hp = 0;
  769. hh = 0;
  770. he = 0;
  771. }
  772. if (et)
  773. {
  774. if (cc != 3)
  775. return 0;
  776. cc -= 2;
  777. }
  778. if (ea)
  779. cc -= 1;
  780. return 1;
  781. }
  782. int
  783. ModAlice::splitaiml (c_char src, fstream &unsorted)
  784. {
  785. cc = 0;
  786. // it now prepares the temp file into the template and pattern files
  787. int patterns = 0, templates = 0, bytecount = 0;
  788. ifstream aiml (src, ios::in | IOS_NOCREATE);
  789. if (!aiml)
  790. {
  791. s->write_botlog ("skipping file %s: %s", src, strerror (errno));
  792. return 1;
  793. }
  794. int linenr = -1;
  795. char line[MAX_LINE_SIZE+1], next[MAX_LINE_SIZE+1], buffer[MAX_LINE_SIZE+1];
  796. aiml.getline (line, MAX_LINE_SIZE);
  797. if (!checkline (line))
  798. {
  799. s->write_botlog ("error %i encountered in file %s, at line %i", cc, src, linenr);
  800. return 0;
  801. }
  802. memset (buffer, 0, MAX_LINE_SIZE);
  803. /* we now make the temp.txt into unsorted.txt and templates.txt
  804. also we exchange some tags for shorthand tags. */
  805. while (aiml.getline (next, MAX_LINE_SIZE))
  806. {
  807. linenr++;
  808. if (!checkline (next))
  809. {
  810. s->write_botlog ("error %i encountered in file %s, at line %i", cc, src, linenr);
  811. return 0;
  812. }
  813. replacer (line);
  814. if (strstr (line, "<pattern>") && strstr (line, "<that>") || strstr (next, "<that>"))
  815. {
  816. while (!strstr (line, "</that>"))
  817. {
  818. if (strlen (line) > MAX_LINE_SIZE)
  819. {
  820. s->write_botlog ("line too long: %s", line);
  821. break;
  822. }
  823. strcpy (line + strlen (line), next);
  824. replacer (line);
  825. linenr++;
  826. aiml.getline (next, MAX_LINE_SIZE);
  827. if (!checkline (next))
  828. {
  829. s->write_botlog ("error %i encountered in file %s, at line %i", cc, src, linenr);
  830. return 0;
  831. }
  832. }
  833. patterns++;
  834. // what we need to print out.. is line till that
  835. strcpy (buffer, strstr (line, "</that>") + 7);
  836. *(strstr (line,"</that>") + 7) = 0;
  837. replace (line, "<pattern>", "");
  838. replace (line, "</pattern>", "");
  839. unsorted << line;
  840. bytecount += strlen (line) - 3;
  841. }
  842. else if (strstr (line, "<pattern>" ))
  843. {
  844. while (!strstr (line, "</pattern>"))
  845. {
  846. if (strlen (line) > MAX_LINE_SIZE)
  847. {
  848. s->write_botlog ("line too long: %s", line);
  849. break;
  850. }
  851. strcpy (line + strlen (line), next);
  852. replacer (line);
  853. linenr++;
  854. aiml.getline (next, MAX_LINE_SIZE);
  855. if (!checkline (next))
  856. {
  857. s->write_botlog ("error %i encountered in file %s, at line %i", cc, src, linenr);
  858. return 0;
  859. }
  860. }
  861. patterns++;
  862. strcpy (buffer, strstr (line, "</pattern>") + 10);
  863. *(strstr (line,"</pattern>") + 10) = 0;
  864. replace (line, "<pattern>", "");
  865. replace (line, "</pattern>", "");
  866. unsorted << line;
  867. bytecount += strlen (line) - 3;
  868. }
  869. if (strstr (line, "<template>"))
  870. {
  871. while (!strstr (line, "</template>"))
  872. {
  873. if (strlen (line) > MAX_LINE_SIZE)
  874. {
  875. s->write_botlog ("line too long: %s", line);
  876. break;
  877. }
  878. strcpy (line + strlen (line), next);
  879. replacer (line);
  880. linenr++;
  881. aiml.getline (next, MAX_LINE_SIZE);
  882. if (!checkline (next))
  883. {
  884. s->write_botlog ("error %i encountered in file %s, at line %i", cc, src, linenr);
  885. return 0;
  886. }
  887. }
  888. long tpos = templatefile.tellp ();
  889. templates++;
  890. if (templates != patterns)
  891. {
  892. s->write_botlog ("pattern/template count mismatch");
  893. mbot_exit ();
  894. }
  895. strcpy (buffer, strstr (line, "</template>") + 11);
  896. *(strstr (line, "</template>") + 11) = 0;
  897. replace (line, "<template>", "");
  898. templatefile << line << '\n';
  899. unsorted << "<tpos=" << tpos << ">\n";
  900. strcpy (buffer, strstr (line, "</template>") + 11);
  901. bytecount += strlen (line) - 3;
  902. }
  903. strcpy (line, buffer);
  904. strcpy (line + strlen (line), next);
  905. }
  906. // this shouldn't be needed
  907. templatefile << "<end of file>\n";
  908. return 1;
  909. }
  910. int
  911. ModAlice::prepare (c_char file)
  912. {
  913. // routine looks through C.aiml for what files to load
  914. fstreamtmp unsorted;
  915. if (!unsorted.is_open ())
  916. {
  917. s->b->write_botlog ("error creating temporary file: %s", strerror (errno));
  918. return 0;
  919. }
  920. char aline[256+1];
  921. ifstream aimlfile (file, ios::in | IOS_NOCREATE);
  922. if (!aimlfile)
  923. {
  924. s->write_botlog ("error opening aimlfile %s: %s", file, strerror (errno));
  925. return 0;
  926. }
  927. while (aimlfile.getline (aline, 256))
  928. if (!splitaiml (aline, unsorted))
  929. return 0;
  930. /* now we alphabetize unsorted.txt by the first letter.
  931. we put this in patterns.txt
  932. we also set chunk, which will tell us where the first letter
  933. is in patterns.txt */
  934. unsorted.seekg (0);
  935. char buffer[MAX_LINE_SIZE+1];
  936. for (int i = 'A'; i <= ('Z' + 1); i++)
  937. {
  938. chunk[i - 'A'] = patternfile.tellp ();
  939. buffer[0] = i;
  940. buffer[1] = 0;
  941. unsorted.seekg (0);
  942. while (unsorted.getline (buffer, MAX_LINE_SIZE))
  943. {
  944. if (i <= 'Z')
  945. {
  946. if (buffer[0] == i)
  947. patternfile << buffer << '\n';
  948. }
  949. else
  950. if ((buffer[0] < 'A') || (buffer[0] > 'Z'))
  951. patternfile << buffer << '\n';
  952. }
  953. unsorted.clear ();
  954. }
  955. return 1;
  956. }
  957. void
  958. ModAlice::substitute (Text &subst, char *text)
  959. {
  960. char spaces[MAX_LINE_SIZE+1], string1[MAX_LINE_SIZE+1],
  961. string2[MAX_LINE_SIZE+1], line[MAX_LINE_SIZE+1], *strtmp;
  962. long long pos1, pos2, pos3, pos4, l;
  963. subst.rewind_text ();
  964. upper (text);
  965. // replace "'" with "`"
  966. size_t i;
  967. for (i = 0; i < strlen (text); i++)
  968. if (text[i] == '\'')
  969. text[i] = '`';
  970. my_strncpy (spaces + 1, text, MAX_LINE_SIZE-1);
  971. spaces[0] = ' ';
  972. l = strlen (spaces);
  973. spaces[l] = ' ';
  974. spaces[l + 1] = 0;
  975. // do replacing from our filename
  976. for (i = subst.line_num; i > 0; i--)
  977. {
  978. my_strncpy (line, subst.get_line (), MAX_LINE_SIZE);
  979. // allow comments
  980. strtmp = strstr (line, "#");
  981. if (strtmp != NULL)
  982. strtmp[0] = 0;
  983. if ((pos1 = strstr (line, "'") - line) < 0
  984. || (char *)0-line == (long long)pos1)
  985. continue;
  986. if ((pos2 = strstr (line + pos1 + 1, "'") - line) < 0
  987. || (char *)0-line == (long long)pos2)
  988. continue;
  989. if ((pos3 = strstr (line + pos2 + 1, "'") - line) < 0
  990. || (char *)0-line == (long long)pos3)
  991. continue;
  992. if ((pos4 = strstr (line + pos3 + 1, "'") - line) < 0
  993. || (char *)0-line == (long long)pos4)
  994. continue;
  995. my_strncpy (string1, line + pos1 + 1, MAX_LINE_SIZE);
  996. string1[pos2 - pos1] = 0;
  997. upper (string1);
  998. my_strncpy (string2, line + pos3 + 1, MAX_LINE_SIZE);
  999. string2[pos4 - pos3] = 0;
  1000. string1[pos2 - pos1 - 1] = string2[pos4 - pos3 - 1] = 0;
  1001. while (replace (spaces, string1, string2));
  1002. }
  1003. strcpy (text, spaces + 1);
  1004. }
  1005. int
  1006. ModAlice::match (c_char text, c_char pattern, int final)
  1007. {
  1008. long long starpos, pos2;
  1009. // if it's a perfect match, return with a YIPPE!
  1010. if (!strcmp (pattern, text))
  1011. return 1;
  1012. // if we just have a '*'
  1013. if ((pattern[0] == '*') && (!pattern[1]))
  1014. {
  1015. if (final)
  1016. strcpy (star, text);
  1017. return 1;
  1018. }
  1019. // check to see if we have a star.. if we don't return false
  1020. if (((starpos = strstr( pattern, "*" ) - pattern) < 0) &&
  1021. ((starpos = strstr( pattern, "_" ) - pattern) < 0))
  1022. return 0;
  1023. // make sure the star isn't in the front
  1024. if (starpos > 0)
  1025. {
  1026. // if the stuff in the front of the star doesn't match, return false
  1027. if (strncmp( pattern, text, starpos ))
  1028. return 0;
  1029. // if we have nothing after the star, return true
  1030. if (!pattern[starpos + 1])
  1031. {
  1032. if (final)
  1033. strcpy (star, text + starpos);
  1034. return 1;
  1035. }
  1036. }
  1037. /* at this point, we either have a star in the front and text
  1038. * HELLO
  1039. or a star in the middle and the text in front matches.
  1040. HELLO * COMPUTER
  1041. this code should be simplified using strcspn()'s and strspn()
  1042. actually.. a better idea.. we reverse both of them
  1043. then we do the same thing we did to begin with.
  1044. nonetheless.. for now.. this code works.. :) */
  1045. char pluseoln[MAX_LINE_SIZE+1], texteoln[MAX_LINE_SIZE+1];
  1046. my_strncpy (texteoln, text, MAX_LINE_SIZE);
  1047. int len = strlen (text);
  1048. texteoln[len] = 10;
  1049. texteoln[len + 1] = 0;
  1050. my_strncpy (pluseoln, pattern + starpos + 1, MAX_LINE_SIZE);
  1051. len = strlen (pluseoln);
  1052. pluseoln[len] = 10;
  1053. pluseoln[len + 1] = 0;
  1054. if ((pos2 = strstr (texteoln, pluseoln) - texteoln) > -1
  1055. && (char *)0-texteoln != pos2)
  1056. {
  1057. if (text[pos2 + strlen (pattern + starpos + 1)] == 0)
  1058. {
  1059. if (final)
  1060. {
  1061. strcpy (star, text + starpos);
  1062. star[pos2 - starpos] = 0;
  1063. }
  1064. return 1;
  1065. }
  1066. }
  1067. return 0;
  1068. }
  1069. void
  1070. ModAlice::print (char *line)
  1071. {
  1072. int start = 1, space = 0, bpos = 0;
  1073. char *pos = pbuffer, *scrap;
  1074. while (*pos)
  1075. {
  1076. if (*pos == ' ')
  1077. space = 1;
  1078. else
  1079. {
  1080. /* this capitilizes I and I'm */
  1081. if ((space) && ((*pos == 'i') || (*pos == 'I')) &&
  1082. ((*(pos + 1) == ' ') || (*(pos + 1) == '\'')))
  1083. {
  1084. line[bpos++] = ' ';
  1085. line[bpos++] = 'I';
  1086. space = 0;
  1087. }
  1088. /* capitilizes the first word in a sentence. */
  1089. else if ((start) && (*pos >= 'a') && (*pos <= 'z'))
  1090. {
  1091. if (space)
  1092. line[bpos++] = ' ';
  1093. line[bpos++] += 'A' - 'a';
  1094. start = space = 0;
  1095. }
  1096. else
  1097. {
  1098. if ((space) && (*(pos +1) != '.'))
  1099. line[bpos++] = ' ';
  1100. line[bpos++] = *pos;
  1101. space = 0;
  1102. }
  1103. start = 0;
  1104. }
  1105. if ((*pos == '.') && (*pos+1 == ' '))
  1106. start = 1;
  1107. pos++;
  1108. }
  1109. // Capitalize current user name
  1110. scrap = strstr (line, getvar ("name", "Human"));
  1111. if ((scrap) && (*scrap >= 'a') && (*scrap <= 'z'))
  1112. *scrap += 'A' - 'a';
  1113. line[bpos] = 0;
  1114. int last = strlen( line ) - 1;
  1115. while ((line[last] == ' ') && (last >= 0))
  1116. line[last--] = 0;
  1117. if ((last >= 0) && (line[last] >= 'a') && (line[last] <= 'z'))
  1118. {
  1119. line[last + 1] = '.';
  1120. line[last + 2] = 0;
  1121. }
  1122. }
  1123. void
  1124. ModAlice::randomize (char *text)
  1125. {
  1126. // this function handles our random tags
  1127. long long pos1;
  1128. int list[MAX_RANDLIST_SIZE];
  1129. char rstring[MAX_LINE_SIZE+1], buffer[MAX_LINE_SIZE+1], *strtmp;
  1130. while ((long long)(pos1 = (char *)strstr (text, "<random>") - (char *)text) > -1
  1131. && (char *)0-text != (long long)pos1)
  1132. {
  1133. my_strncpy (rstring, text + pos1 + 8, MAX_LINE_SIZE);
  1134. strtmp = strstr (rstring, "</random>");
  1135. if (strtmp != NULL)
  1136. {
  1137. strtmp[0] = 0;
  1138. int items = 0;
  1139. long long pos, last = -1;
  1140. while ((pos = (long long)(strstr (rstring + last + 1, "<li>") - rstring)) > -1
  1141. && (char *)0-rstring != (long long)pos)
  1142. {
  1143. list[items++] = pos + 4;
  1144. last = pos;
  1145. }
  1146. int rnd = random_num (items);
  1147. my_strncpy (buffer, text, MAX_LINE_SIZE);
  1148. strcpy (buffer + pos1, rstring + list[rnd]);
  1149. if (strstr (buffer, "</li>"))
  1150. *strstr (buffer, "</li>") = 0;
  1151. strcpy (buffer + strlen (buffer), " ");
  1152. strcpy (buffer + strlen (buffer), strstr (text, "</random>") + 9);
  1153. strcpy (text, buffer);
  1154. }
  1155. else
  1156. {
  1157. // Handle erroneous randoms
  1158. my_strncpy (rstring, text + pos1 + 8, MAX_LINE_SIZE);
  1159. strcpy (text, rstring);
  1160. }
  1161. }
  1162. }
  1163. void
  1164. ModAlice::reevaluate (char *line)
  1165. {
  1166. char varname[MAX_VARNAME_SIZE+1];
  1167. char value[MAX_VARVAL_SIZE+1];
  1168. char scrap[MAX_LINE_SIZE+1];
  1169. char *pos;
  1170. lower (star);
  1171. randomize (line);
  1172. while ((pos = strstr (line, "<think>")))
  1173. {
  1174. my_strncpy (scrap, pos + 7, MAX_LINE_SIZE);
  1175. *strstr (scrap, "</think>") = 0;
  1176. reevaluate (scrap);
  1177. strremove (line, "<think>", "</think>");
  1178. }
  1179. while (replace (line, "<star/>", star));
  1180. while (replace (line, "<that/>", that));
  1181. while ((pos = strstr(line,"<person>")))
  1182. {
  1183. my_strncpy (scrap, pos + 8, MAX_LINE_SIZE);
  1184. *strstr (scrap, "</person>") = 0;
  1185. substitute (personfile, scrap);
  1186. lower (scrap);
  1187. strremove (line, "son>", "</person>");
  1188. replace (line, "<per", scrap);
  1189. }
  1190. while ((pos = strstr (line, "<person2>")))
  1191. {
  1192. my_strncpy (scrap, pos + 9, MAX_LINE_SIZE);
  1193. *strstr (scrap, "</person2>") = 0;
  1194. substitute (person2file, scrap);
  1195. lower (scrap);
  1196. strremove (line, "son2>", "</person2>");
  1197. replace (line, "<per", scrap);
  1198. }
  1199. while ((pos = strstr (line, "<personf>")))
  1200. {
  1201. my_strncpy (scrap, pos + 9, MAX_LINE_SIZE);
  1202. *strstr (scrap, "</personf>") = 0;
  1203. substitute (personffile, scrap);
  1204. lower (scrap);
  1205. strremove (line, "sonf>", "</personf>");
  1206. replace (line, "<per", scrap);
  1207. }
  1208. while ((pos = strstr (line, "<getvar")))
  1209. {
  1210. if (!(pos =strstr (pos + 8, "name")))
  1211. {
  1212. strremove (line, "<getvar", "/>");
  1213. continue;
  1214. }
  1215. pos = strstr (pos, "\"") + 1;
  1216. // ok.. now pos = foo" default="bar" /> or... pos = foo"
  1217. my_strncpy (scrap, pos, MAX_LINE_SIZE);
  1218. char *lix = strstr (scrap, "\"");
  1219. if (lix != NULL)
  1220. lix[0] = 0;
  1221. my_strncpy (varname, scrap, MAX_VARNAME_SIZE);
  1222. pos = strstr (line, "<getvar");
  1223. // this is if we don't have a default
  1224. if (!(strstr (pos + 8, "default")))
  1225. {
  1226. my_strncpy (scrap, pos, MAX_LINE_SIZE);
  1227. *strstr (line, "<getvar") = 0;
  1228. strremove (scrap, "<getvar","/>");
  1229. strncat (line, getvar (varname, "weird"), MAX_LINE_SIZE-strlen (line));
  1230. strncat (line, scrap, MAX_LINE_SIZE-strlen (line));
  1231. continue;
  1232. }
  1233. // insert code here to deal with defaults
  1234. }
  1235. while ((pos = strlstr (line, "<setvar")))
  1236. {
  1237. char *holder = pos;
  1238. int setreturn;
  1239. pos = strstr (pos, "name=\"") + 6;
  1240. my_strncpy (scrap, pos, MAX_LINE_SIZE);
  1241. *strstr (scrap, "\"") = 0;
  1242. my_strncpy (varname, scrap, MAX_VARNAME_SIZE);
  1243. pos = strstr (pos, ">") +1;
  1244. strcpy (scrap, pos);
  1245. char *lix = strstr (scrap, "</setvar>");
  1246. if (lix != NULL)
  1247. *lix = 0;
  1248. my_strncpy (value, scrap, MAX_VARVAL_SIZE);
  1249. setreturn = setvar (0, varname, value);
  1250. if (setreturn == 1)
  1251. {
  1252. // print name
  1253. strremove (holder, "<setvar", "\"");
  1254. strremove (holder, "\"", "</setvar>");
  1255. }
  1256. if (setreturn == 2)
  1257. {
  1258. strremove (holder, "<setvar", ">");
  1259. replace (holder, "</setvar>", "");
  1260. }
  1261. }
  1262. while ((pos = strstr (line, "<srai>")))
  1263. {
  1264. if (++srai_num > MAX_SRAI)
  1265. break;
  1266. my_strncpy (scrap, pos + 6, MAX_LINE_SIZE);
  1267. *strstr (scrap, "</srai>") = 0;
  1268. upper (scrap);
  1269. my_strncpy (scrap, respond2 (scrap), MAX_LINE_SIZE);
  1270. // is this too cheap?
  1271. strremove (line, "ai>", "</srai>");
  1272. replace (line, "<sr", scrap);
  1273. }
  1274. while ((pos = strstr (line, "<system>")))
  1275. {
  1276. my_strncpy (scrap, pos + 8, MAX_LINE_SIZE);
  1277. *strstr (scrap, "</system>") = 0;
  1278. system (scrap);
  1279. strremove (line, "<system>", "</system>");
  1280. }
  1281. while ((pos = strstr (line, "<seen>")))
  1282. {
  1283. my_strncpy (scrap, pos + 6, MAX_LINE_SIZE);
  1284. *strstr (scrap, "</seen>") = 0;
  1285. // if it's in a channel with the bot
  1286. for (int i = 0; i < s->channel_num; i++)
  1287. if (CHANNELS[i]->user_index (scrap) != -1)
  1288. {
  1289. snprintf (line, MAX_LINE_SIZE, "%s is currently online.", scrap);
  1290. return;
  1291. }
  1292. // else get the seen module and ask it
  1293. time_t t = -1;
  1294. Module *m;
  1295. s->b->modules.rewind ();
  1296. while ((m = (Module *)s->b->modules.next ()) != NULL)
  1297. if (strcmp (*m, "seen") == 0)
  1298. break;
  1299. s->b->modules.restore_current ();
  1300. if (m != NULL)
  1301. {
  1302. time_t (*server2seentime)(NetServer *, c_char) = (time_t(*)(NetServer *, c_char))m->getsym ("server2seentime");
  1303. if (server2seentime != NULL)
  1304. t = server2seentime (s, scrap);
  1305. }
  1306. if (t == -1)
  1307. switch (random_num (2))
  1308. {
  1309. case 0: snprintf (line, MAX_LINE_SIZE, "Humm, I don't remember %s.", scrap); break;
  1310. case 1: snprintf (line, MAX_LINE_SIZE, "I don't remember %s... Tell %s to buy me more RAM.", scrap, getvar ("botmaster", "mirage")); break;
  1311. }
  1312. else
  1313. {
  1314. char timestr[MSG_SIZE+1];
  1315. my_strncpy (timestr, asctime (localtime (&t)), MSG_SIZE);
  1316. timestr[strlen (timestr) - 1] = 0;
  1317. snprintf (line, MAX_LINE_SIZE, "I last saw %s on %s.", scrap, timestr);
  1318. }
  1319. }
  1320. while ((pos = strstr (line, "<word>")))
  1321. {
  1322. my_strncpy (scrap, pos+6, MAX_LINE_SIZE);
  1323. *strstr (scrap, "</word>") = 0;
  1324. Module *m;
  1325. s->b->modules.rewind ();
  1326. while ((m = (Module *)s->b->modules.next ()) != NULL)
  1327. {
  1328. if (strcmp (*m, "word") == 0)
  1329. break;
  1330. }
  1331. s->b->modules.restore_current ();
  1332. char text[MSG_SIZE+1];
  1333. text[0] = 0;
  1334. if (m != NULL)
  1335. {
  1336. void (*server2wordtext)(NetServer *, c_char, char *, size_t) = (void(*)(NetServer *, c_char, char *, size_t))m->getsym ("server2wordtext");
  1337. if (server2wordtext != NULL)
  1338. server2wordtext (s, scrap, text, MSG_SIZE);
  1339. }
  1340. if (text[0] == 0)
  1341. snprintf (line, MAX_LINE_SIZE, "Not defined... lousy word anyway :D");
  1342. else
  1343. {
  1344. switch (random_num (5))
  1345. {
  1346. case 0: snprintf (line, MAX_LINE_SIZE, "I heard that %s is %s", scrap, text); break;
  1347. case 1: snprintf (line, MAX_LINE_SIZE, "Someone said %s is %s", scrap, text); break;
  1348. case 2: snprintf (line, MAX_LINE_SIZE, "%s is %s", scrap, text); break;
  1349. case 3: snprintf (line, MAX_LINE_SIZE, "I know that %s is %s", scrap, text); break;
  1350. case 4: snprintf (line, MAX_LINE_SIZE, "It's public that %s is %s", scrap, text); break;
  1351. }
  1352. }
  1353. }
  1354. strcpy (that, line);
  1355. }
  1356. char *
  1357. ModAlice::respond2 (char *text)
  1358. {
  1359. char *pos, line[MAX_LINE_SIZE+1], buffer[MAX_LINE_SIZE+1],
  1360. capthat[MAX_LINE_SIZE+1];
  1361. long tpos, bestpos = 0;
  1362. int alpha, thatused;
  1363. star[0] = pbuffer[0] = 0;
  1364. best = "";
  1365. alpha = ((text[0] >= 'A') && (text[0] <= 'Z'));
  1366. long long tval;
  1367. int bestline = -1, linenr = -1;
  1368. patternfile.clear ();
  1369. if (alpha)
  1370. patternfile.seekg (chunk[text[0] - 'A']);
  1371. else
  1372. patternfile.seekg (chunk[26]);
  1373. while (!(!patternfile))
  1374. {
  1375. linenr++;
  1376. patternfile.getline (line, MAX_LINE_SIZE);
  1377. /* this gets fired if Alice didn't find an exact
  1378. match in it's own letter */
  1379. if ((alpha) && (line[0] != text[0]))
  1380. {
  1381. alpha = 0;
  1382. patternfile.clear ();
  1383. patternfile.seekg (chunk[26]);
  1384. continue;
  1385. }
  1386. /* this strips the position out of the end of the pattern.
  1387. if the line doesn't contain a <tops get the next line. */
  1388. if ((tval = strstr (line, "<tpos=") - line) < 0
  1389. || (char *)0-line == (long long)tval)
  1390. continue;
  1391. my_strncpy (buffer, line + tval + 6, MAX_LINE_SIZE);
  1392. if (strstr (buffer, ">"))
  1393. *strstr (buffer, ">") = 0;
  1394. line[tval] = 0;
  1395. tpos = atol (buffer);
  1396. thatused = 0;
  1397. while (replace (line, "<getvar name=\"botname\"/>", getvar ("botname", "DarkSun")));
  1398. // check to see if <that> was used
  1399. if ((pos = strstr (line, "<that>")))
  1400. {
  1401. // we copy that into buffer
  1402. my_strncpy (buffer, pos + 6, MAX_LINE_SIZE);
  1403. // we chop that off our line
  1404. *strstr (line, "<that>") = 0;
  1405. if (strstr (buffer, "</that>"))
  1406. *strstr (buffer, "</that>") = 0;
  1407. /* now buffer holds our that from the pattern
  1408. that holds our last statement. */
  1409. my_strncpy (capthat, that, MAX_LINE_SIZE);
  1410. upper (capthat);
  1411. cleaner (capthat);
  1412. if (!match (capthat, buffer, 0 ))
  1413. continue;
  1414. thatused = 1;
  1415. }
  1416. spacetrim (line);
  1417. if (!match (text, line, 0))
  1418. continue;
  1419. if ((strcmp (text, line) == 0) || (thatused))
  1420. {
  1421. best = line;
  1422. bestline = linenr;
  1423. bestpos = tpos;
  1424. break;
  1425. }
  1426. if ((strcmp (line, best) < 0) && (bestline > -1))
  1427. continue;
  1428. best = line;
  1429. bestline = linenr;
  1430. bestpos = tpos;
  1431. }
  1432. match (text, best, 1);
  1433. templatefile.clear ();
  1434. templatefile.seekg (bestpos);
  1435. templatefile.getline (line, MAX_LINE_SIZE);
  1436. buffer[0] = 10;
  1437. buffer[1] = 0;
  1438. if (strstr (line, "</template>"))
  1439. *strstr (line, "</template>") = 0;
  1440. reevaluate (line);
  1441. strcpy (pbuffer, line);
  1442. return pbuffer;
  1443. }
  1444. ////////////////////
  1445. // module managing
  1446. ////////////////////
  1447. ModAlice *
  1448. server2alice (NetServer *s)
  1449. {
  1450. ModAlice *a;
  1451. alice_list->rewind ();
  1452. while ((a = (ModAlice *)alice_list->next ()) != NULL)
  1453. if (a->s == s)
  1454. return a;
  1455. return NULL;
  1456. }
  1457. // events watcher to parse privmsg
  1458. void
  1459. alice_event (NetServer *s)
  1460. {
  1461. if (EVENT != EVENT_PRIVMSG
  1462. || CMD[3][0] == '' // ctcp
  1463. || (CMD[2][0] >= '0' && CMD[2][0] <= '9')) // dcc chat
  1464. return;
  1465. char *alans;
  1466. ModAlice *a = server2alice (s);
  1467. if (a == NULL)
  1468. return;
  1469. // if it's a channel
  1470. if ((CMD[2][0] == '#') || ((CMD[2][0] == '@') && (CMD[2][1] == '#')))
  1471. {
  1472. if (strncasecmp (CMD[3], s->nick, s->nick.getlen ()) == 0)
  1473. {
  1474. char *buf = strstr (CMD[3], " ");
  1475. if (buf == NULL)
  1476. return;
  1477. alans = a->respond (buf);
  1478. stripurl (alans);
  1479. strip_crlf (alans);
  1480. SEND_TEXT (DEST, "%s: %s", SOURCE, alans);
  1481. }
  1482. return;
  1483. }
  1484. // pvt with the bot
  1485. char buf[MSG_SIZE+1];
  1486. my_strncpy (buf, CMD[3], MSG_SIZE);
  1487. strtok (buf, " ");
  1488. // only respond if it's not a mbot command
  1489. if (s->script.cmd_get (buf) != NULL)
  1490. return;
  1491. alans = a->respond (CMD[3]);
  1492. stripurl (alans);
  1493. strip_crlf (alans);
  1494. SEND_TEXT (DEST, "%s", alans);
  1495. }
  1496. // configuration file's local parser
  1497. void
  1498. alice_conf (NetServer *s, c_char bufread)
  1499. {
  1500. char buf[5][MSG_SIZE+1];
  1501. strsplit (bufread, buf, 4);
  1502. if (strcasecmp (buf[0], "alice") == 0)
  1503. {
  1504. if (buf[2][0] == 0)
  1505. s->b->conf_error ("sintax error: use \"alice initfile varsfile [loghandle]\"");
  1506. Log *log = NULL;
  1507. if (buf[3][0] != 0)
  1508. {
  1509. log = s->b->log_get (buf[3]);
  1510. if (log == NULL)
  1511. {
  1512. snprintf (buf[0], MSG_SIZE, "inexistant loghandle: %s", buf[3]);
  1513. s->b->conf_error (buf[0]);
  1514. }
  1515. }
  1516. ModAlice *a = server2alice (s);
  1517. if (a != NULL)
  1518. s->b->conf_error ("alice already defined in this server");
  1519. a = new ModAlice (s, buf[1], buf[2], log);
  1520. if (!a->initialized)
  1521. s->b->conf_error ("error initializing alice");
  1522. alice_list->add ((void *)a);
  1523. s->script.events.add ((void *)alice_event);
  1524. }
  1525. }
  1526. void
  1527. alice_stop (void)
  1528. {
  1529. ModAlice *a;
  1530. alice_list->rewind ();
  1531. while ((a = (ModAlice *)alice_list->next ()) != NULL)
  1532. {
  1533. a->s->script.events.del ((void *)alice_event);
  1534. delete a;
  1535. }
  1536. delete alice_list;
  1537. }
  1538. // module initialization
  1539. void
  1540. alice_start (void)
  1541. {
  1542. alice_list = new List ();
  1543. }