1: <?php
2:
3: namespace Budabot\User\Modules;
4:
5: use Budabot\Core\StopExecutionException;
6: use Exception;
7:
8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21:
22: class ShoppingController {
23:
24: 25: 26: 27:
28: public $moduleName;
29:
30:
31: public $chatBot;
32:
33:
34: public $text;
35:
36:
37: public $util;
38:
39:
40: public $http;
41:
42:
43: public $db;
44:
45:
46: public $settingManager;
47:
48:
49: public $banController;
50:
51:
52: public $playerManager;
53:
54:
55: public $itemsController;
56:
57:
58: public $logger;
59:
60:
61: public function setup() {
62: $this->db->loadSQLFile($this->moduleName, "shopping_messages");
63: $this->db->loadSQLFile($this->moduleName, "shopping_items");
64:
65: $this->settingManager->add($this->moduleName, "shop_message_age", "How long to keep shopping messages", "edit", "time", "10d", "1d;2d;5d;10d;15d;20d");
66: $this->settingManager->add($this->moduleName, "shop_database", "Where to look for shopping messages", "edit", "text", "http://shopping.budabot.jkbff.com/shopping/index.php", "local;http://shopping.budabot.jkbff.com/shopping/index.php");
67: }
68:
69: 70: 71: 72: 73: 74:
75: public function shopCommand($message, $channel, $sender, $sendto, $args) {
76: if (count($args) == 4) {
77: $minQl = $args[1];
78: $maxQl = $args[2];
79: $search = $args[3];
80: } else if (count($args) == 3) {
81: $minQl = $args[1];
82: $maxQl = $args[1];
83: $search = $args[2];
84: } else {
85: $minQl = 0;
86: $maxQl = 500;
87: $search = $args[1];
88: }
89:
90: $shopDatabase = $this->settingManager->get('shop_database');
91: if ($shopDatabase == 'local') {
92: $results = $this->searchLocal($search, $minQl, $maxQl);
93: } else {
94: $results = $this->searchRemote($shopDatabase, $search, $minQl, $maxQl);
95: }
96:
97: $count = count($results);
98: if ($count == 0) {
99: $msg = "No results were found matching your search criteria.";
100: } else {
101: $blob = '';
102: forEach ($results as $result) {
103: $senderLink = $this->text->makeUserlink($result->sender);
104: $timeString = $this->util->unixtimeToReadable(time() - $result->time, false);
105: $post = preg_replace('|<a href="itemref://(\d+)/(\d+)/(\d+)">([^<]+)</a>|', "<a href='itemref://\\1/\\2/\\3'>\\4</a>", $result->message);
106: $blob .= "[$senderLink]: {$post} - <highlight>($timeString ago)<end>\n\n";
107: }
108: $msg = $this->text->makeBlob("Shopping Results for '$search' ($count)", $blob);
109: }
110:
111: $sendto->reply($msg);
112: }
113:
114: public function searchRemote($url, $search, $minQl, $maxQl) {
115: $params = array(
116: 'server' => $this->chatBot->vars['dimension'],
117: 'search' => $search,
118: 'minql' => $minQl,
119: 'maxql' => $maxQl,
120: 'bot' => 'budabot'
121: );
122: $response = $this->http->get($url)->withQueryParams($params)->waitAndReturnResponse();
123: if (!empty($response->error)) {
124: throw new Exception($response->error);
125: } else if (substr($response->body, 0, 5) == 'Error') {
126: throw new Exception($response->body);
127: } else {
128: return json_decode($response->body);
129: }
130: }
131:
132: public function searchLocal($search, $minQl, $maxQl) {
133: list($query, $params) = $this->util->generateQueryFromParams(explode(' ', $search), 's1.name');
134:
135: $params []= $minQl;
136: $params []= $maxQl;
137:
138: $sql = "
139: SELECT
140: sender,
141: message,
142: MAX(dt) as time
143: FROM
144: shopping_items s1
145: JOIN shopping_messages s2
146: ON s1.message_id = s2.id
147: WHERE
148: s2.dimension = <dim>
149: AND $query
150: AND s1.ql >= ?
151: AND s1.ql <= ?
152: GROUP BY
153: sender,
154: message
155: ORDER BY
156: MAX(dt) DESC
157: LIMIT
158: 40";
159:
160: return $this->db->query($sql, $params);
161: }
162:
163: 164: 165: 166:
167: public function captureShoppingMessagesEvent($eventObj) {
168: $packet = $eventObj->packet;
169:
170: $b = unpack("C*", $packet->args[0]);
171:
172:
173: if ($b[1] != 134) {
174: return;
175: }
176:
177: $charId = $packet->args[1];
178: $channel = $this->chatBot->get_gname($packet->args[0]);
179: $sender = $this->chatBot->lookup_user($charId);
180: $message = $packet->args[2];
181:
182: if ($this->banController->isBanned($charId)) {
183: return;
184: }
185:
186: $this->logger->logChat($channel, $sender, $message);
187:
188: $this->processShoppingMessage($channel, $sender, $message);
189: }
190:
191: 192: 193: 194:
195: public function removeOldMessagesEvent($eventObj) {
196: $dt = time() - $this->settingManager->get('shop_message_age');
197:
198: $sql = "DELETE FROM shopping_messages WHERE dt < ?";
199: $this->db->exec($sql, $dt);
200:
201: $sql = "DELETE FROM shopping_items WHERE message_id NOT IN (SELECT id FROM shopping_messages)";
202: $this->db->exec($sql);
203: }
204:
205: public function processShoppingMessage($channel, $sender, $message) {
206: $message = preg_replace("|<font(.+)>|U", "", $message);
207: $message = preg_replace("|</font>|U", "", $message);
208:
209:
210: $messageType = 1;
211: if (preg_match("/^(.{0,3})wtb/i", $message)) {
212: $messageType = 2;
213: } else if (preg_match("/^(.{0,3})wtt/i", $message)) {
214: $messageType = 3;
215: } else if (preg_match("/^(.{0,3})wth/i", $message)) {
216: $messageType = 4;
217: }
218:
219: $matches = array();
220: $pattern = '|<a href="itemref://(\d+)/(\d+)/(\d+)">([^<]+)</a>|';
221: preg_match_all($pattern, $message, $matches, PREG_SET_ORDER);
222:
223: $sql = "INSERT INTO shopping_messages (dimension, message_type, channel, bot, sender, dt, message) VALUES ('<dim>', ?, ?, '<myname>', ?, ?, ?)";
224: $this->db->exec($sql, $messageType, $channel, $sender, time(), $message);
225: $id = $this->db->lastInsertId();
226:
227: forEach ($matches as $match) {
228: $lowid = $match[1];
229: $highid = $match[2];
230: $ql = $match[3];
231: $name = $match[4];
232:
233: $item = $this->itemsController->findById($lowid);
234: $iconid = 0;
235: if ($item !== null) {
236: $iconid = $item->icon;
237: }
238:
239: $sql = "INSERT INTO shopping_items (message_id, lowid, highid, ql, iconid, name) VALUES (?, ?, ?, ?, ?, ?)";
240: $this->db->exec($sql, $id, $lowid, $highid, $ql, $iconid, $name);
241: }
242:
243: $this->playerManager->getByName($sender);
244: }
245:
246: public function parseSpamMessage($message) {
247: $rawmsg = $this->stripColors($message);
248: if (preg_match_all("/\\[([^\\]]+)\\] (.+?) \\[([^\\]]+)\\]/s", $rawmsg, $arr, PREG_SET_ORDER) > 0) {
249: } else {
250: $this->logger->log("WARN", "Invalid spam message format: $rawmsg");
251: }
252: return $arr;
253: }
254:
255: private function parseSpambotMessage($eventObj) {
256: $arr = $this->parseSpamMessage($eventObj->message);
257: forEach ($arr as $entry) {
258: $channel = $entry[1];
259: $text = $entry[2];
260: $sender = $entry[3];
261:
262: $this->processShoppingMessage("$eventObj->sender - $channel", $sender, $text);
263: }
264: }
265: }