MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 1 | // channeld.c |
| 2 | // |
| 3 | // $Id: channeld.c 9138 2015-02-03 21:46:56Z Zesstra $ |
| 4 | // |
| 5 | |
| 6 | #pragma strong_types |
| 7 | #pragma no_shadow // keine Shadowing... |
| 8 | #pragma no_clone |
| 9 | #pragma no_inherit |
| 10 | #pragma save_types |
| 11 | |
| 12 | #include <sys_debug.h> |
| 13 | #include <lpctypes.h> |
| 14 | #include <wizlevels.h> |
| 15 | |
| 16 | #include <properties.h> |
| 17 | #include <config.h> |
| 18 | #include <language.h> |
| 19 | |
| 20 | #define NEED_PROTOTYPES |
| 21 | #include "channel.h" |
| 22 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 23 | #define CMNAME "<MasteR>" |
| 24 | #define CHANNEL_SAVE "/p/daemon/save/channeld" |
| 25 | #define MEMORY "/secure/memory" |
| 26 | #define TIMEOUT (time() - 60) |
| 27 | #define CMDS ({C_FIND, C_LIST, C_JOIN, C_LEAVE, C_SEND, C_NEW}) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 28 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 29 | /* list of channels and their corresponding data (members, etc.) |
| 30 | channels = ([string channelname : ({ ({object* members}), |
| 31 | closure access_rights, |
| 32 | string channel_info, |
| 33 | string|object master_object, |
| 34 | string channelname }) ]) */ |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 35 | private nosave mapping channels; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 36 | //private nosave mapping lowerch; // unused |
| 37 | |
| 38 | /* channel history |
| 39 | mapping channelH = ([ string channelname : ({ string channelname, |
| 40 | string sender, |
| 41 | string msg, |
| 42 | int msg_type }) ]) */ |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 43 | private nosave mapping channelH; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 44 | |
| 45 | /* list of global channelmaster stats |
| 46 | mapping stats: ([ "time" : int object_time(), |
| 47 | "boot" : string load_name(previous_object()), |
| 48 | "new" : int total_channels_created, |
| 49 | "disposed" : int total_channels_removed ]) */ |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 50 | private nosave mapping stats; |
| 51 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 52 | /* channel cache |
| 53 | mapping channelC = ([ string channelname : ({ string I_NAME, |
| 54 | string I_INFO, |
| 55 | int time() }) ]) */ |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 56 | private mapping channelC; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 57 | |
| 58 | /* list of players' banned commands, if any |
| 59 | mapping channelB = ([ string playername : ({ string* banned_commands })])*/ |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 60 | private mapping channelB; |
| 61 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 62 | /* timeout cache for player commands (timeout = 60 s, see above) |
| 63 | ensures that the same command is only executed once per minute, max |
| 64 | mapping Tcmd = ([ "lag": int timestamp, |
| 65 | "uptime": int timestamp, |
| 66 | "statistik": int timestamp]) */ |
| 67 | private mapping Tcmd = ([]); |
| 68 | |
| 69 | /* Flag to indicate that data changes have occurred and that we need saving |
| 70 | in the next save_object() run. |
| 71 | set to 0 or 1 */ |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 72 | private int save_me_soon; |
| 73 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 74 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 75 | // BEGIN OF THE CHANNEL MASTER ADMINISTRATIVE PART |
| 76 | |
| 77 | #define RECV 0 |
| 78 | #define SEND 1 |
| 79 | #define FLAG 2 |
| 80 | |
| 81 | // Channel flags |
| 82 | // Levelbeschraenkungen gegen Magierlevel (query_wiz_level) pruefen, nicht |
| 83 | // P_LEVEL. |
| 84 | #define F_WIZARD 1 |
| 85 | // Keine Gaeste. ;-) |
| 86 | #define F_NOGUEST 2 |
| 87 | |
| 88 | private nosave mapping admin = m_allocate(0, 3); |
| 89 | |
| 90 | int check(string ch, object pl, string cmd) |
| 91 | { |
| 92 | int level; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 93 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 94 | if ((admin[ch, FLAG] & F_NOGUEST) && pl->QueryGuest()) |
| 95 | return 0; |
| 96 | |
| 97 | if ((admin[ch, FLAG] & F_WIZARD) && query_wiz_level(pl) < SEER_LVL) |
| 98 | return 0; |
| 99 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 100 | level = (admin[ch, FLAG] & F_WIZARD |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 101 | ? query_wiz_level(pl) |
| 102 | : pl->QueryProp(P_LEVEL)); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 103 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 104 | switch (cmd) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 105 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 106 | case C_FIND: |
| 107 | case C_LIST: |
| 108 | case C_JOIN: |
| 109 | if (admin[ch, RECV] == -1) |
| 110 | return 0; |
| 111 | if (admin[ch, RECV] <= level) |
| 112 | return 1; |
| 113 | break; |
| 114 | |
| 115 | case C_SEND: |
| 116 | if (admin[ch, SEND] == -1) |
| 117 | return 0; |
| 118 | if (admin[ch, SEND] <= level) |
| 119 | return 1; |
| 120 | break; |
| 121 | |
| 122 | case C_LEAVE: |
| 123 | return 1; |
| 124 | |
| 125 | default: |
| 126 | break; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 127 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 128 | return (0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 129 | } |
| 130 | |
| 131 | private int CountUser(mapping l) |
| 132 | { |
Arathorn | 5ea1536 | 2018-11-15 22:22:05 +0100 | [diff] [blame] | 133 | mapping n = ([]); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 134 | walk_mapping(l, function void (string chan_name, mixed * chan_data) |
| 135 | { |
| 136 | n += mkmapping(chan_data[I_MEMBER]); |
| 137 | }); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 138 | return sizeof(n); |
| 139 | } |
| 140 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 141 | private void banned(string n, string* cmds, string res) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 142 | { |
| 143 | res += sprintf("%s [%s], ", capitalize(n), implode(cmds, ",")); |
| 144 | } |
| 145 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 146 | void ChannelMessage(mixed msg) |
| 147 | { |
| 148 | string ret, mesg; |
| 149 | mixed lag; |
| 150 | int max, rekord; |
| 151 | string tmp; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 152 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 153 | if (msg[1] == this_object() || !stringp(msg[2]) || |
| 154 | msg[0] != CMNAME || previous_object() != this_object()) |
| 155 | return; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 156 | |
| 157 | mesg = lower_case(msg[2]); |
| 158 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 159 | if (!strstr("hilfe", mesg) && sizeof(mesg) <= 5) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 160 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 161 | ret = "Folgende Kommandos gibt es: hilfe, lag, up[time], statistik, bann"; |
| 162 | } |
| 163 | else if (!strstr("lag", mesg) && sizeof(mesg) <= 3) |
| 164 | { |
| 165 | // TODO: invert logic to make this better understandable, e.g. |
| 166 | // if ( CMD_AVAILABLE("lag") ) and rearrange code block |
| 167 | if (Tcmd["lag"] > TIMEOUT) |
| 168 | return; |
| 169 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 170 | Tcmd["lag"] = time(); |
| 171 | lag = "/p/daemon/lag-o-daemon"->read_ext_lag_data(); |
| 172 | ret = sprintf("Lag: %.1f%%/60, %.1f%%/15, %.1f%%/5, %.1f%%/1, " |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 173 | "%.1f%%/20s, %.1f%%/2s", |
| 174 | lag[5], lag[4], lag[3], lag[2], lag[1], lag[0]); |
| 175 | call_out(#'send, 2, CMNAME, this_object(), ret); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 176 | ret = query_load_average(); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 177 | } |
| 178 | // TODO: move this logic to a function with a self-explanatory name |
| 179 | else if (!strstr("uptime", mesg) && sizeof(mesg) <= 6) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 180 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 181 | if (Tcmd["uptime"] > TIMEOUT) |
| 182 | return; |
| 183 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 184 | Tcmd["uptime"] = time(); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 185 | |
| 186 | if (file_size("/etc/maxusers") <= 0) |
| 187 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 188 | ret = "Diese Information liegt nicht vor."; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 189 | } |
| 190 | else |
| 191 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 192 | sscanf(read_file("/etc/maxusers"), "%d %s", max, tmp); |
| 193 | sscanf(read_file("/etc/maxusers.ever"), "%d %s", rekord, tmp); |
| 194 | ret = sprintf("Das MUD laeuft jetzt %s. Es sind momentan %d Spieler " |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 195 | "eingeloggt; das Maximum lag heute bei %d und der Rekord " |
| 196 | "bisher ist %d.", uptime(), sizeof(users()), max, rekord); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 197 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 198 | } |
| 199 | else if (!strstr("statistik", mesg) && sizeof(mesg) <= 9) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 200 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 201 | if (Tcmd["statistik"] > TIMEOUT) |
| 202 | return; |
| 203 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 204 | Tcmd["statistik"] = time(); |
| 205 | ret = sprintf( |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 206 | "Im Moment sind insgesamt %d Ebenen mit %d Teilnehmern aktiv.\n" |
| 207 | "Der %s wurde das letzte mal am %s von %s neu gestartet.\n" |
| 208 | "Seitdem wurden %d Ebenen neu erzeugt und %d zerstoert.\n", |
| 209 | sizeof(channels), CountUser(channels), CMNAME, |
| 210 | dtime(stats["time"]), stats["boot"], stats["new"], stats["dispose"]); |
| 211 | } |
| 212 | else if (!strstr(mesg, "bann")) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 213 | { |
| 214 | string pl, cmd; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 215 | |
| 216 | if (mesg == "bann") |
| 217 | { |
| 218 | if (sizeof(channelB)) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 219 | { |
| 220 | ret = ""; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 221 | walk_mapping(channelB, #'banned, &ret); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 222 | ret = "Fuer folgende Spieler besteht ein Bann: " + ret; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 223 | } |
| 224 | else |
| 225 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 226 | ret = "Zur Zeit ist kein Bann aktiv."; |
| 227 | } |
| 228 | } |
| 229 | else |
| 230 | { |
| 231 | if (sscanf(mesg, "bann %s %s", pl, cmd) == 2 && IS_DEPUTY(msg[1])) |
| 232 | { |
| 233 | pl = lower_case(pl); |
| 234 | cmd = lower_case(cmd); |
| 235 | |
| 236 | if (member(CMDS, cmd) != -1) |
| 237 | { |
| 238 | if (!pointerp(channelB[pl])) |
| 239 | channelB[pl] = ({}); |
| 240 | |
| 241 | if (member(channelB[pl], cmd) != -1) |
| 242 | channelB[pl] -= ({ cmd }); |
| 243 | else |
| 244 | channelB[pl] += ({ cmd }); |
| 245 | ret = "Fuer '" + capitalize(pl) + "' besteht " |
| 246 | + (sizeof(channelB[pl]) ? |
| 247 | "folgender Bann: " + implode(channelB[pl], ", ") : |
| 248 | "kein Bann mehr."); |
| 249 | |
| 250 | if (!sizeof(channelB[pl])) |
| 251 | channelB = m_copy_delete(channelB, pl); |
| 252 | |
| 253 | save_object(CHANNEL_SAVE); |
| 254 | } |
| 255 | else |
| 256 | { |
| 257 | ret = "Das Kommando '" + cmd + "' ist unbekannt. " |
| 258 | "Erlaubte Kommandos: "+ implode(CMDS, ", "); |
| 259 | } |
| 260 | } |
| 261 | else |
| 262 | { |
| 263 | if (!IS_ARCH(msg[1])) |
| 264 | return; |
| 265 | else |
| 266 | ret = "Syntax: bann <name> <kommando>"; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 267 | } |
| 268 | } |
| 269 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 270 | else if (mesg == "lust") |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 271 | { |
| 272 | mixed t, up; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 273 | |
| 274 | if (Tcmd["lag"] > TIMEOUT || |
| 275 | Tcmd["statistik"] > TIMEOUT || |
| 276 | Tcmd["uptime"] > TIMEOUT) |
| 277 | return; |
| 278 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 279 | Tcmd["lag"] = time(); |
| 280 | Tcmd["statistik"] = time(); |
| 281 | Tcmd["uptime"] = time(); |
| 282 | lag = "/p/daemon/lag-o-daemon"->read_lag_data(); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 283 | sscanf(read_file("/etc/maxusers"), "%d %s", max, tmp); |
| 284 | sscanf(read_file("/etc/maxusers.ever"), "%d %s", rekord, tmp); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 285 | t = time() - last_reboot_time(); |
| 286 | up = ""; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 287 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 288 | if (t >= 86400) |
| 289 | up += sprintf("%dT", t / 86400); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 290 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 291 | if (t >= 3600) |
| 292 | up += sprintf("%dh", (t = t % 86400) / 3600); |
| 293 | |
| 294 | if (t > 60) |
| 295 | up += sprintf("%dm", (t = t % 3600) / 60); |
| 296 | |
| 297 | up += sprintf("%ds", t % 60); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 298 | ret = sprintf("%.1f%%/15 %.1f%%/1 %s %d:%d:%d E:%d T:%d", |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 299 | lag[1], lag[2], up, sizeof(users()), max, rekord, |
| 300 | sizeof(channels), CountUser(channels)); |
| 301 | } |
| 302 | else |
| 303 | { |
| 304 | return; |
| 305 | } |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 306 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 307 | call_out(#'send, 2, CMNAME, this_object(), ret); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 308 | } |
| 309 | |
| 310 | // setup() -- set up a channel and register it |
| 311 | // arguments are stored in the following order: |
| 312 | // ({ channel name, |
| 313 | // receive level, send level, |
| 314 | // flags, |
| 315 | // description, |
| 316 | // master obj |
| 317 | // }) |
| 318 | private void setup(mixed c) |
| 319 | { |
| 320 | closure cl; |
| 321 | object m; |
| 322 | string d; |
| 323 | d = "- Keine Beschreibung -"; |
| 324 | m = this_object(); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 325 | |
| 326 | if (sizeof(c) && sizeof(c[0]) > 1 && c[0][0] == '\\') |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 327 | c[0] = c[0][1..]; |
| 328 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 329 | switch (sizeof(c)) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 330 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 331 | case 6: |
| 332 | if (!stringp(c[5]) || !sizeof(c[5]) || |
| 333 | (catch(m = load_object(c[5]); publish) || |
| 334 | !objectp(m))) |
| 335 | m = this_object(); |
| 336 | |
| 337 | case 5: |
| 338 | d = stringp(c[4]) || closurep(c[4]) ? c[4] : d; |
| 339 | |
| 340 | case 4: |
| 341 | admin[c[0], FLAG] = to_int(c[3]); |
| 342 | |
| 343 | case 3: |
| 344 | admin[c[0], SEND] = to_int(c[2]); |
| 345 | |
| 346 | case 2: |
| 347 | admin[c[0], RECV] = to_int(c[1]); |
| 348 | break; |
| 349 | |
| 350 | case 0: |
| 351 | default: |
| 352 | return; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 353 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 354 | |
| 355 | switch (new(c[0], m, d)) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 356 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 357 | case E_ACCESS_DENIED: |
| 358 | log_file("CHANNEL", sprintf("[%s] %s: %O: error, access denied\n", |
| 359 | dtime(time()), c[0], m)); |
| 360 | break; |
| 361 | |
| 362 | default: |
| 363 | break; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 364 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 365 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 366 | return; |
| 367 | } |
| 368 | |
| 369 | void initialize() |
| 370 | { |
| 371 | mixed tmp; |
Zesstra@Morgengrauen | 3b569c8 | 2016-07-18 20:22:08 +0200 | [diff] [blame] | 372 | #if !defined(__TESTMUD__) && MUDNAME=="MorgenGrauen" |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 373 | tmp = read_file(object_name(this_object()) + ".init"); |
Zesstra@Morgengrauen | 3b569c8 | 2016-07-18 20:22:08 +0200 | [diff] [blame] | 374 | #else |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 375 | tmp = read_file(object_name(this_object()) + ".init.testmud"); |
Zesstra@Morgengrauen | 3b569c8 | 2016-07-18 20:22:08 +0200 | [diff] [blame] | 376 | #endif |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 377 | |
Zesstra@Morgengrauen | 2b22937 | 2016-07-20 23:59:54 +0200 | [diff] [blame] | 378 | if (!stringp(tmp)) |
| 379 | return; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 380 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 381 | tmp = regexp(old_explode(tmp, "\n"), "^[^#]"); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 382 | tmp = map(tmp, #'regexplode, "[^:][^:]*$|[ \\t]*:[ \\t]*"); |
| 383 | tmp = map(tmp, #'regexp, "^[^: \\t]"); |
| 384 | map(tmp, #'setup); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 385 | } |
| 386 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 387 | // BEGIN OF THE CHANNEL MASTER IMPLEMENTATION |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 388 | |
Zesstra@Morgengrauen | 2b22937 | 2016-07-20 23:59:54 +0200 | [diff] [blame] | 389 | protected void create() |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 390 | { |
| 391 | seteuid(getuid()); |
| 392 | restore_object(CHANNEL_SAVE); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 393 | |
| 394 | if (!channelC) |
| 395 | channelC = ([]); |
| 396 | |
| 397 | if (!channelB) |
| 398 | channelB = ([]); |
| 399 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 400 | channels = ([]); |
| 401 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 402 | /* Die Channel-History wird nicht nur lokal sondern auch noch im Memory |
| 403 | gespeichert, dadurch bleibt sie auch ueber ein Reload erhalten. |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 404 | Der folgende Code versucht, den Zeiger aus dem Memory zu holen. Falls |
| 405 | das nicht moeglich ist, wird ein neuer erzeugt und gegebenenfalls im |
| 406 | Memory abgelegt. */ |
| 407 | |
| 408 | // Hab ich die noetigen Rechte im Memory? |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 409 | if (call_other(MEMORY, "HaveRights")) |
| 410 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 411 | // Objektpointer laden |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 412 | channelH = (mixed) call_other(MEMORY, "Load", "History"); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 413 | |
| 414 | // Wenns nich geklappt hat, hat der Memory noch keinen Zeiger, dann |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 415 | if (!mappingp(channelH)) { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 416 | // Zeiger erzeugen |
| 417 | channelH = ([]); |
| 418 | // und in den Memory schreiben |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 419 | call_other(MEMORY, "Save", "History", channelH); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 420 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 421 | } |
| 422 | else |
| 423 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 424 | // Keine Rechte im Memory, dann wird mit einem lokalen Zeiger gearbeitet. |
| 425 | channelH = ([]); |
| 426 | } |
| 427 | |
| 428 | stats = (["time": time(), |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 429 | "boot": capitalize(getuid(previous_object()) || "<Unbekannt>")]); |
| 430 | new (CMNAME, this_object(), "Zentrale Informationen zu den Ebenen"); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 431 | initialize(); |
| 432 | map_objects(efun::users(), "RegisterChannels"); |
| 433 | this_object()->send(CMNAME, this_object(), |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 434 | sprintf("%d Ebenen mit %d Teilnehmern initialisiert.", |
| 435 | sizeof(channels), |
| 436 | CountUser(channels))); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 437 | } |
| 438 | |
| 439 | // reset() and cache_to() - Cache Timeout, remove timed out cached channels |
| 440 | // SEE: new, send |
| 441 | private int cache_to(string key, mapping m, int t) |
| 442 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 443 | if (!pointerp(m[key]) || m[key][2] + 43200 > t) |
| 444 | return 1; |
| 445 | |
| 446 | return (0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 447 | } |
| 448 | |
| 449 | varargs void reset(int nonstd) |
| 450 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 451 | channelC = filter_indices(channelC, #'cache_to, channelC, time()); |
| 452 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 453 | if (save_me_soon) |
| 454 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 455 | save_me_soon = 0; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 456 | save_object(CHANNEL_SAVE); |
| 457 | } |
| 458 | } |
| 459 | |
| 460 | // name() - define the name of this object. |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 461 | string name() |
| 462 | { |
| 463 | return CMNAME; |
| 464 | } |
| 465 | |
| 466 | string Name() |
| 467 | { |
| 468 | return CMNAME; |
| 469 | } |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 470 | |
| 471 | // access() - check access by looking for the right argument types and |
| 472 | // calling access closures respectively |
| 473 | // SEE: new, join, leave, send, list, users |
| 474 | // Note: <pl> is usually an object, only the master supplies a string during |
| 475 | // runtime error handling. |
| 476 | varargs private int access(mixed ch, mixed pl, string cmd, string txt) |
| 477 | { |
| 478 | mixed co, m; |
| 479 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 480 | if (!stringp(ch) || !sizeof(ch = lower_case(ch)) || !channels[ch]) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 481 | return 0; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 482 | |
| 483 | if (!channels[ch][I_ACCESS] || !previous_object(1) || !extern_call() || |
| 484 | previous_object(1) == this_object() || |
| 485 | (stringp(channels[ch][I_MASTER]) && |
| 486 | previous_object(1) == find_object(channels[ch][I_MASTER])) || |
| 487 | getuid(previous_object(1)) == ROOTID) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 488 | return 2; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 489 | |
| 490 | if (!objectp(pl) || |
| 491 | ((previous_object(1) != pl) && (previous_object(1) != this_object()))) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 492 | return 0; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 493 | |
| 494 | if (pointerp(channelB[getuid(pl)]) && |
| 495 | member(channelB[getuid(pl)], cmd) != -1) |
| 496 | return 0; |
| 497 | |
| 498 | if (stringp(channels[ch][I_MASTER]) && |
| 499 | (!(m = find_object(channels[ch][I_MASTER])) || |
| 500 | (!to_object(channels[ch][I_ACCESS]) || |
| 501 | get_type_info(channels[ch][I_ACCESS])[1]))) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 502 | { |
| 503 | string err; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 504 | |
| 505 | if (!objectp(m)) |
| 506 | err = catch(load_object(channels[ch][I_MASTER]); publish); |
| 507 | |
| 508 | if (!err && |
| 509 | ((!to_object(channels[ch][I_ACCESS]) || |
| 510 | get_type_info(channels[ch][I_ACCESS])[1]) && |
| 511 | !closurep(channels[ch][I_ACCESS] = |
| 512 | symbol_function("check", find_object(channels[ch][I_MASTER]))))) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 513 | { |
| 514 | log_file("CHANNEL", sprintf("[%s] %O -> %O\n", |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 515 | dtime(time()), channels[ch][I_MASTER], |
| 516 | err)); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 517 | channels = m_copy_delete(channels, ch); |
| 518 | return 0; |
| 519 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 520 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 521 | this_object()->join(ch, find_object(channels[ch][I_MASTER])); |
| 522 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 523 | |
| 524 | if (closurep(channels[ch][I_ACCESS])) |
| 525 | return funcall(channels[ch][I_ACCESS], |
| 526 | channels[ch][I_NAME], pl, cmd, &txt); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 527 | } |
| 528 | |
| 529 | // new() - create a new channel |
| 530 | // a channel with name 'ch' is created, the player is the master |
| 531 | // info may contain a string which describes the channel or a closure |
| 532 | // to display up-to-date information, check may contain a closure |
| 533 | // called when a join/leave/send/list/users message is received |
| 534 | // SEE: access |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 535 | #define IGNORE "^/xx" |
| 536 | |
| 537 | varargs int new(string ch, object pl, mixed info) |
| 538 | { |
| 539 | mixed pls; |
| 540 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 541 | if (!objectp(pl) || !stringp(ch) || !sizeof(ch) || |
| 542 | channels[lower_case(ch)] || (pl == this_object() && extern_call()) || |
| 543 | sizeof(channels) >= MAX_CHANNELS || |
| 544 | sizeof(regexp(({ object_name(pl) }), IGNORE)) || |
| 545 | (pointerp(channelB[getuid(pl)]) && |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 546 | member(channelB[getuid(pl)], C_NEW) != -1)) |
| 547 | return E_ACCESS_DENIED; |
| 548 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 549 | if (!info) |
| 550 | { |
| 551 | if (channelC[lower_case(ch)]) |
| 552 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 553 | ch = channelC[lower_case(ch)][0]; |
| 554 | info = channelC[lower_case(ch)][1]; |
| 555 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 556 | else |
| 557 | { |
| 558 | return E_ACCESS_DENIED; |
| 559 | } |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 560 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 561 | else |
| 562 | { |
| 563 | channelC[lower_case(ch)] = ({ ch, info, time() }); |
| 564 | } |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 565 | |
| 566 | pls = ({ pl }); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 567 | channels[lower_case(ch)] = ({ |
| 568 | pls, |
| 569 | symbol_function("check", pl) || #'check, info, |
| 570 | (!living(pl) && !clonep(pl) && pl != this_object() |
| 571 | ? object_name(pl) |
| 572 | : pl), |
| 573 | ch}); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 574 | |
| 575 | // ChannelH fuer einen Kanal nur dann initialisieren, wenn es sie noch nich gibt. |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 576 | if (!pointerp(channelH[lower_case(ch)])) |
| 577 | channelH[lower_case(ch)] = ({}); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 578 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 579 | if (pl != this_object()) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 580 | log_file("CHANNEL.new", sprintf("[%s] %O: %O %O\n", |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 581 | dtime(time()), ch, pl, info)); |
| 582 | |
| 583 | if (!pl->QueryProp(P_INVIS)) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 584 | this_object()->send(CMNAME, pl, |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 585 | "laesst die Ebene '" + ch + "' entstehen.", MSG_EMOTE); |
| 586 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 587 | stats["new"]++; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 588 | save_me_soon = 1; |
| 589 | return (0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 590 | } |
| 591 | |
| 592 | // join() - join a channel |
| 593 | // this function checks whether the player 'pl' is allowed to join |
| 594 | // the channel 'ch' and add if successful, one cannot join a channel |
| 595 | // twice |
| 596 | // SEE: leave, access |
| 597 | int join(string ch, object pl) |
| 598 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 599 | if (!funcall(#'access,&ch, pl, C_JOIN)) |
| 600 | return E_ACCESS_DENIED; |
| 601 | |
| 602 | if (member(channels[ch][I_MEMBER], pl) != -1) |
| 603 | return E_ALREADY_JOINED; |
| 604 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 605 | channels[ch][I_MEMBER] += ({ pl }); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 606 | return (0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 607 | } |
| 608 | |
| 609 | // leave() - leave a channel |
| 610 | // the access check in this function is just there for completeness |
| 611 | // one should always be allowed to leave a channel. |
| 612 | // if there are no players left on the channel it will vanish, unless |
| 613 | // its master is this object. |
| 614 | // SEE: join, access |
| 615 | int leave(string ch, object pl) |
| 616 | { |
| 617 | int pos; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 618 | |
| 619 | if (!funcall(#'access,&ch, pl, C_LEAVE)) |
| 620 | return E_ACCESS_DENIED; |
| 621 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 622 | channels[ch][I_MEMBER] -= ({0}); // kaputte Objekte erstmal raus |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 623 | |
| 624 | if ((pos = member(channels[ch][I_MEMBER], pl)) == -1) |
| 625 | return E_NOT_MEMBER; |
| 626 | |
| 627 | if (pl == channels[ch][I_MASTER] && sizeof(channels[ch][I_MEMBER]) > 1) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 628 | { |
| 629 | channels[ch][I_MASTER] = channels[ch][I_MEMBER][1]; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 630 | |
| 631 | if (!pl->QueryProp(P_INVIS)) |
| 632 | this_object()->send(ch, pl, "uebergibt die Ebene an " + |
| 633 | channels[ch][I_MASTER]->name(WEN) + ".", MSG_EMOTE); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 634 | } |
| 635 | channels[ch][I_MEMBER][pos..pos] = ({ }); |
| 636 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 637 | if (!sizeof(channels[ch][I_MEMBER]) && !stringp(channels[ch][I_MASTER])) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 638 | { |
| 639 | // delete the channel that has no members |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 640 | if (!pl->QueryProp(P_INVIS)) |
| 641 | this_object()->send(CMNAME, pl, |
| 642 | "verlaesst als "+ |
| 643 | (pl->QueryProp(P_GENDER) == 1 ? "Letzter" : "Letzte")+ |
| 644 | " die Ebene '"+channels[ch][I_NAME]+"', worauf diese sich in " |
| 645 | "einem Blitz oktarinen Lichts aufloest.", MSG_EMOTE); |
| 646 | |
| 647 | channelC[lower_case(ch)] = |
| 648 | ({ channels[ch][I_NAME], channels[ch][I_INFO], time() }); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 649 | m_delete(channels, lower_case(ch)); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 650 | // Wird ein Channel entfernt, wird auch seine History geloescht |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 651 | // TODO: this foils the attempts at creating a persistent channel |
| 652 | // history via /secure/memory.c |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 653 | channelH = m_copy_delete(channelH, lower_case(ch)); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 654 | stats["dispose"]++; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 655 | save_me_soon = 1; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 656 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 657 | return (0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 658 | } |
| 659 | |
| 660 | // send() - send a message to all recipients of the specified channel 'ch' |
| 661 | // checks if 'pl' is allowed to send a message and sends if success- |
| 662 | // ful a message with type 'type' |
| 663 | // 'pl' must be an object, the message is attributed to it. e.g. |
| 664 | // ignore checks use it. It can be != previous_object() |
| 665 | // SEE: access, ch.h |
| 666 | varargs int send(string ch, object pl, string msg, int type) |
| 667 | { |
| 668 | int a; |
| 669 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 670 | if (!(a = funcall(#'access, &ch, pl, C_SEND, &msg))) |
| 671 | return E_ACCESS_DENIED; |
| 672 | |
| 673 | if (a < 2 && member(channels[ch][I_MEMBER], pl) == -1) |
| 674 | return E_NOT_MEMBER; |
| 675 | |
| 676 | if (!msg || !stringp(msg) || !sizeof(msg)) |
| 677 | return E_EMPTY_MESSAGE; |
| 678 | |
| 679 | map_objects(channels[ch][I_MEMBER], "ChannelMessage", |
| 680 | ({ channels[ch][I_NAME], pl, msg, type })); |
| 681 | |
| 682 | if (sizeof(channelH[ch]) > MAX_HIST_SIZE) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 683 | channelH[ch] = channelH[ch][1..]; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 684 | |
| 685 | channelH[ch] += |
| 686 | ({ ({ channels[ch][I_NAME], |
| 687 | (stringp(pl) |
| 688 | ? pl |
| 689 | : (pl->QueryProp(P_INVIS) |
| 690 | ? "/(" + capitalize(getuid(pl)) + ")$" |
| 691 | : "") |
| 692 | + (pl->Name(WER, 2) || "<Unbekannt>")), |
| 693 | msg + " <" + strftime("%a, %H:%M:%S") + ">\n", |
| 694 | type }) }); |
| 695 | return (0); |
| 696 | } |
| 697 | |
| 698 | private void clean(string n, mixed a) |
| 699 | { |
| 700 | a[0] -= ({ 0 }); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 701 | } |
| 702 | |
| 703 | // list() - list all channels, that are at least receivable by 'pl' |
| 704 | // returns a mapping, |
| 705 | // SEE: access, channels |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 706 | mixed list(object pl) |
| 707 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 708 | mapping chs = filter_indices(channels, #'access, pl, C_LIST); |
| 709 | walk_mapping(chs, #'clean); |
| 710 | |
| 711 | if (!sizeof(chs)) |
| 712 | return E_ACCESS_DENIED; |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 713 | return deep_copy(chs); |
| 714 | } |
| 715 | |
| 716 | // find() - find a channel by its name (may be partial) |
| 717 | // returns an array for multiple results and 0 for no matching name |
| 718 | // SEE: access |
| 719 | mixed find(string ch, object pl) |
| 720 | { |
| 721 | mixed chs, s; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 722 | |
| 723 | if (stringp(ch)) |
| 724 | ch = lower_case(ch); |
| 725 | |
| 726 | if (!sizeof(regexp(({ch}), "^[<>a-z0-9#-]*$"))) |
| 727 | return 0; // RUM |
| 728 | |
| 729 | if (!sizeof(chs = regexp(m_indices(channels), "^" + ch + "$"))) |
| 730 | chs = regexp(m_indices(channels), "^" + ch); |
| 731 | |
| 732 | if ((s = sizeof(chs)) > 1) |
| 733 | { |
| 734 | if (sizeof(chs = filter(chs, #'access, pl, C_FIND)) == 1) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 735 | return channels[chs[0]][I_NAME]; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 736 | else |
| 737 | return chs; |
| 738 | } |
| 739 | |
| 740 | return ((s && funcall(#'access,chs[0], pl, C_FIND)) |
| 741 | ? channels[chs[0]][I_NAME] |
| 742 | : 0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 743 | } |
| 744 | |
| 745 | // history() - get the history of a channel |
| 746 | // SEE: access |
| 747 | mixed history(string ch, object pl) |
| 748 | { |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 749 | if (!funcall(#'access, &ch, pl, C_JOIN)) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 750 | return E_ACCESS_DENIED; |
| 751 | return deep_copy(channelH[ch]); |
| 752 | } |
| 753 | |
| 754 | // remove - remove a channel (wird aus der Shell aufgerufen) |
| 755 | // SEE: new |
| 756 | mixed remove(string ch, object pl) |
| 757 | { |
| 758 | mixed members; |
| 759 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 760 | if (previous_object() != this_object()) |
| 761 | { |
| 762 | if (!stringp(ch) || |
| 763 | pl != this_player() || this_player() != this_interactive() || |
| 764 | this_interactive() != previous_object() || |
| 765 | !IS_ARCH(this_interactive())) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 766 | return E_ACCESS_DENIED; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 767 | } |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 768 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 769 | if (channels[lower_case(ch)]) |
| 770 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 771 | channels[lower_case(ch)][I_MEMBER] = |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 772 | filter_objects(channels[lower_case(ch)][I_MEMBER], |
| 773 | "QueryProp", P_CHANNELS); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 774 | map(channels[lower_case(ch)][I_MEMBER], |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 775 | function mixed(object listener) |
| 776 | { |
| 777 | string* chans = listener->QueryProp(P_CHANNELS); |
| 778 | chans -= ({lower_case(ch)}); |
| 779 | ({string*})listener->SetProp(P_CHANNELS, chans); |
| 780 | }); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 781 | channels = m_copy_delete(channels, lower_case(ch)); |
| 782 | |
| 783 | // Wird ein Channel entfernt, wird auch seine History geloescht |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 784 | if (pointerp(channelH[lower_case(ch)])) |
| 785 | channelH = m_copy_delete(channelH, lower_case(ch)); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 786 | |
| 787 | stats["dispose"]++; |
| 788 | } |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 789 | |
| 790 | if (!channelC[lower_case(ch)]) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 791 | return E_ACCESS_DENIED; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 792 | |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 793 | channelC = m_copy_delete(channelC, lower_case(ch)); |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 794 | save_me_soon = 1; |
| 795 | return (0); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 796 | } |
| 797 | |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 798 | // Wird aus der Shell aufgerufen |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 799 | mixed clear_history(string ch) |
| 800 | { |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 801 | // Sicherheitsabfragen |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 802 | if (previous_object() != this_object()) |
| 803 | { |
| 804 | if (!stringp(ch) || |
| 805 | this_player() != this_interactive() || |
| 806 | this_interactive() != previous_object() || |
| 807 | !IS_ARCH(this_interactive())) |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 808 | return E_ACCESS_DENIED; |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 809 | } |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 810 | |
| 811 | // History des Channels loeschen |
Arathorn | 19459eb | 2019-11-30 00:45:51 +0100 | [diff] [blame^] | 812 | if (pointerp(channelH[lower_case(ch)])) |
| 813 | channelH[lower_case(ch)] = ({}); |
MG Mud User | 88f1247 | 2016-06-24 23:31:02 +0200 | [diff] [blame] | 814 | |
| 815 | return 0; |
| 816 | } |